

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=&#34;auto&#34;>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon%2032x32.ico">
  <link rel="icon" href="/img/favicon%2032x32.ico">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
    <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="">
  <meta name="author" content="hypocrite30">
  <meta name="keywords" content="">
  
  <title>Spring Security 5.1.4 - hypocrite30</title>

  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4.0.0/github-markdown.min.css" />
  <link  rel="stylesheet" href="/lib/hint/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@10.4.0/styles/idea.min.css" />
    
  

  
    <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" />
  



<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_kmeydafke9r.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"hypocrite30.gitee.io","root":"/","version":"1.8.9","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"right","visible":"hover","icon":"§"},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"copy_btn":true,"image_zoom":{"enable":true},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":2},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"baidu":"b5f391eebc7eaea88e68a49d5924e381","google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null}}};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.3.0"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/">&nbsp;<strong>Hypocrite30 BLOG</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/links/">
                <i class="iconfont icon-link-fill"></i>
                友链
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" data-toggle="modal" data-target="#modalSearch">&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;</a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" href="javascript:">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner" id="banner" parallax=true
         style="background: url('/img/postPage.jpg') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="Spring Security 5.1.4">
              
            </span>

            
              <div class="mt-3">
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2021-04-14 22:20" pubdate>
        2021年4月14日 晚上
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      10.5k 字
    </span>
  

  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      200
       分钟
    </span>
  

  
  
    
      <!-- 不蒜子统计文章PV -->
      <span id="busuanzi_container_page_pv" style="display: none">
        <i class="iconfont icon-eye" aria-hidden="true"></i>
        <span id="busuanzi_value_page_pv"></span> 次
      </span>
    
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">Spring Security 5.1.4</h1>
            
              <p class="note note-info">
                
                  本文最后更新于：2021年4月14日 晚上
                
              </p>
            
            <div class="markdown-body">
              <h1 id="Spring-Security"><a href="#Spring-Security" class="headerlink" title="Spring Security"></a>Spring Security</h1><hr>
<blockquote>
<p>基于 Spring Security 5.1.4.RELEASE</p>
</blockquote>
<h2 id="1-基本概念"><a href="#1-基本概念" class="headerlink" title="1. 基本概念"></a>1. 基本概念</h2><h3 id="1-1-认证"><a href="#1-1-认证" class="headerlink" title="1.1 认证"></a>1.1 认证</h3><ul>
<li>判断一个用户的身份<strong>是否合法</strong>的过程，用户去访问系统资源时系统要求验证用户的身份信息，身份合法方可继续访问，不合法则拒绝访问。常见的用户身份认证方式有：用户名密码登录，二维码登录，手机短信登录，指纹认证等方式。</li>
</ul>
<h3 id="1-2-会话"><a href="#1-2-会话" class="headerlink" title="1.2 会话"></a>1.2 会话</h3><p>认证通过后，为了避免用户的每次操作都进行认证可将用户的信息保证在会话中。会话就是系统为了<strong>保持当前</strong><br><strong>用户的登录状态</strong>所提供的机制。</p>
<ul>
<li><code>session</code>方式</li>
</ul>
<p>认证成功后，服务器生成用户相关数据保存在session(当前会话)中，发给客户端 <code>session_id</code>，客户机存在 <code>cookie</code> 中，下次客户端请求会带上 session_id ，服务器可以验证 session 数据，检验合法性，当用户退出系统或 session 过期，session_id 就无效。</p>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210408205018967.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li><code>token</code>方式</li>
</ul>
<p>用户认证成功后，服务端生成一个<code>token</code>发给客户端，客户端可以放到 cookie 或 localStorage<br>等存储中，每次请求时带上 token，服务端收到token通过验证后即可确认用户身份。</p>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210408205204737.png" srcset="/img/loading.gif" lazyload></p>
<h4 id="区别："><a href="#区别：" class="headerlink" title="区别："></a>区别：</h4><ul>
<li><p>基于session的认证方式由Servlet规范定制，服务端要存储session信息需要<strong>占用内存资源</strong>，客户端<strong>需要支持</strong><br><strong>cookie</strong>；</p>
</li>
<li><p>基于token的方式则一般不需要服务端存储token，并且不限制客户端的存储方式。如今移动互联网时代<br>更多类型的客户端需要接入系统，系统多是采用<strong>前后端分离</strong>的架构进行实现，所以基于token的方式更适合。</p>
</li>
</ul>
<h3 id="1-3-授权"><a href="#1-3-授权" class="headerlink" title="1.3 授权"></a>1.3 授权</h3><p>用户认证通过根据用户的权限来控制用户访问资源的过程，拥有资源的访问权限则正常访问，没有权限则拒绝访问。</p>
<h4 id="区别于认证"><a href="#区别于认证" class="headerlink" title="区别于认证"></a>区别于认证</h4><ul>
<li><p>认证是为了保证<strong>用户身份的合法性</strong></p>
</li>
<li><p>授权则是为了更细粒度的对<strong>隐私数据</strong>进行划分，授权是在<strong>认证通过后</strong>发生的，控制不同的用户能够访问不同的资源。</p>
</li>
</ul>
<h4 id="数据模型"><a href="#数据模型" class="headerlink" title="数据模型"></a>数据模型</h4><p>授权可简单理解为：<strong>主体</strong> 对 <strong>资源</strong> 进行 怎样的<strong>操作</strong>「权限/许可」，权限是需要与资源进行关联的，否则权限没有意义。</p>
<p>三者的关系图：</p>
<img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210409161516911.png" srcset="/img/loading.gif" lazyload style="zoom:125%;" />

<ul>
<li>不同的权限可以管理不同的资源，用户需要有对应权限才能访问资源。</li>
<li>引入一个 「角色」概念，用户归类于<strong>角色</strong>，角色拥有相应<strong>权限</strong>，最后根据权限访问<strong>资源</strong></li>
</ul>
<img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210409161944605.png" srcset="/img/loading.gif" lazyload style="zoom:125%;" />

<ul>
<li>用户【用户id，账号，密码，…】</li>
<li>角色【角色id，角色名称，…】</li>
<li>权限【权限id，权限标识，权限名称，资源id，…】</li>
<li>资源【资源id，资源名称，访问地址，…】<ul>
<li>用户 - 角色 【用户id，角色id，…】</li>
<li>角色 - 权限 【角色id，权限id，….】</li>
</ul>
</li>
</ul>
<hr>
<p>企业开发将 资源和权限合为一张权限表：</p>
<img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210409162541875.png" srcset="/img/loading.gif" lazyload style="zoom:130%;" />

<ul>
<li>资源【资源id、资源名称、访问地址、…】</li>
<li>权限【权限id、权限标识、权限名称、资源id、…】<ul>
<li><strong>合并</strong>为：权限【权限id、权限标识、权限名称、资源名称、资源访问地址、…】</li>
</ul>
</li>
</ul>
<h3 id="1-4-RBAC"><a href="#1-4-RBAC" class="headerlink" title="1.4 RBAC"></a>1.4 RBAC</h3><h4 id="1-4-1-基于角色的访问控制"><a href="#1-4-1-基于角色的访问控制" class="headerlink" title="1.4.1 基于角色的访问控制"></a>1.4.1 基于角色的访问控制</h4><p><code>Role-Based Access Control</code> 按照角色进行授权。</p>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210409163724890.png" srcset="/img/loading.gif" lazyload></p>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">if</span>(主体.hasRole(<span class="hljs-string">&quot;总经理角色id&quot;</span>)) &#123;<br>    查询工资<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>如果上图所需角色添加为老板和总经理，此时就要改代码</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">if</span>(主体.hasRole(<span class="hljs-string">&quot;总经理角色id&quot;</span>) ||  主体.hasRole(<span class="hljs-string">&quot;老板角色id&quot;</span>)) &#123;<br>    查询工资<br>&#125;<br></code></pre></div></td></tr></table></figure>
<h4 id="1-4-2-基于资源的访问控制"><a href="#1-4-2-基于资源的访问控制" class="headerlink" title="1.4.2 基于资源的访问控制"></a>1.4.2 基于资源的访问控制</h4><p><code>Resource-Based Access Control</code> 按照资源（权限）进行授权。</p>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210409164139236.png" srcset="/img/loading.gif" lazyload></p>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">if</span>(主体.hasPermission(<span class="hljs-string">&quot;查询工资权限标识&quot;</span>)) &#123;<br>    查询工资<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>代码统一，增加<strong>可拓展性</strong>。</li>
</ul>
<h2 id="2-基于Session的认证方式「手动实现security」"><a href="#2-基于Session的认证方式「手动实现security」" class="headerlink" title="2. 基于Session的认证方式「手动实现security」"></a>2. 基于Session的认证方式「手动实现security」</h2><h3 id="2-1-环境搭建"><a href="#2-1-环境搭建" class="headerlink" title="2.1 环境搭建"></a>2.1 环境搭建</h3><blockquote>
<p>基于 SpringMVC 5.1.5.RELEASE, Servlet3.0实现</p>
</blockquote>
<h4 id="2-1-1-创建Maven工程"><a href="#2-1-1-创建Maven工程" class="headerlink" title="2.1.1 创建Maven工程"></a>2.1.1 创建Maven工程</h4><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">project</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">         <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">modelVersion</span>&gt;</span>4.0.0<span class="hljs-tag">&lt;/<span class="hljs-name">modelVersion</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.xxx.security<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>security-springmvc<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.0-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">packaging</span>&gt;</span>war<span class="hljs-tag">&lt;/<span class="hljs-name">packaging</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">properties</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">project.build.sourceEncoding</span>&gt;</span>UTF-8<span class="hljs-tag">&lt;/<span class="hljs-name">project.build.sourceEncoding</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">maven.compiler.source</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">maven.compiler.source</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">maven.compiler.target</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">maven.compiler.target</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">properties</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-webmvc<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.1.5.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- 不添加该依赖tomcat7:run无法运行项目 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>javax.servlet<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>javax.servlet-api<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.0.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>provided<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.projectlombok<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>lombok<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.18.8<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">build</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">finalName</span>&gt;</span>security-springmvc<span class="hljs-tag">&lt;/<span class="hljs-name">finalName</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">pluginManagement</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">plugins</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.tomcat.maven<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>tomcat7-maven-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span><br>                        <span class="hljs-tag">&lt;<span class="hljs-name">port</span>&gt;</span>8080<span class="hljs-tag">&lt;/<span class="hljs-name">port</span>&gt;</span><br>                        <span class="hljs-tag">&lt;<span class="hljs-name">path</span>&gt;</span>/<span class="hljs-tag">&lt;/<span class="hljs-name">path</span>&gt;</span><br>                        <span class="hljs-tag">&lt;<span class="hljs-name">uriEncoding</span>&gt;</span>utf-8<span class="hljs-tag">&lt;/<span class="hljs-name">uriEncoding</span>&gt;</span><br>                    <span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span><br>                <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>maven-compiler-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span><br>                        <span class="hljs-tag">&lt;<span class="hljs-name">source</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">source</span>&gt;</span><br>                        <span class="hljs-tag">&lt;<span class="hljs-name">target</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">target</span>&gt;</span><br>                    <span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span><br>                <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span><br><br>                <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>maven-resources-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span><br>                        <span class="hljs-tag">&lt;<span class="hljs-name">encoding</span>&gt;</span>utf-8<span class="hljs-tag">&lt;/<span class="hljs-name">encoding</span>&gt;</span><br>                        <span class="hljs-tag">&lt;<span class="hljs-name">useDefaultDelimiters</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">useDefaultDelimiters</span>&gt;</span><br>                        <span class="hljs-tag">&lt;<span class="hljs-name">resources</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">resource</span>&gt;</span><br>                                <span class="hljs-tag">&lt;<span class="hljs-name">directory</span>&gt;</span>src/main/resources<span class="hljs-tag">&lt;/<span class="hljs-name">directory</span>&gt;</span><br>                                <span class="hljs-tag">&lt;<span class="hljs-name">filtering</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">filtering</span>&gt;</span><br>                                <span class="hljs-tag">&lt;<span class="hljs-name">includes</span>&gt;</span><br>                                    <span class="hljs-tag">&lt;<span class="hljs-name">include</span>&gt;</span>**/*<span class="hljs-tag">&lt;/<span class="hljs-name">include</span>&gt;</span><br>                                <span class="hljs-tag">&lt;/<span class="hljs-name">includes</span>&gt;</span><br>                            <span class="hljs-tag">&lt;/<span class="hljs-name">resource</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">resource</span>&gt;</span><br>                                <span class="hljs-tag">&lt;<span class="hljs-name">directory</span>&gt;</span>src/main/java<span class="hljs-tag">&lt;/<span class="hljs-name">directory</span>&gt;</span><br>                                <span class="hljs-tag">&lt;<span class="hljs-name">includes</span>&gt;</span><br>                                    <span class="hljs-tag">&lt;<span class="hljs-name">include</span>&gt;</span>**/*.xml<span class="hljs-tag">&lt;/<span class="hljs-name">include</span>&gt;</span><br>                                <span class="hljs-tag">&lt;/<span class="hljs-name">includes</span>&gt;</span><br>                            <span class="hljs-tag">&lt;/<span class="hljs-name">resource</span>&gt;</span><br>                        <span class="hljs-tag">&lt;/<span class="hljs-name">resources</span>&gt;</span><br>                    <span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span><br>                <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">plugins</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">pluginManagement</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">build</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">project</span>&gt;</span><br></code></pre></div></td></tr></table></figure>
<ul>
<li>Web项目，packaging打包方式为 war</li>
<li>使用<code>tomcat7-maven-plugin</code>插件来运行工程</li>
</ul>
<h4 id="2-1-2-Spring容器配置"><a href="#2-1-2-Spring容器配置" class="headerlink" title="2.1.2 Spring容器配置"></a>2.1.2 Spring容器配置</h4><ul>
<li>config包下定义<code>ApplicationConfig</code>，它对应web.xml中<code>ContextLoaderListener</code>的配置「Servlet3.0不用xml配置」</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Configuration</span> <span class="hljs-comment">//相当于applicationContext.xml</span><br><span class="hljs-meta">@ComponentScan(basePackages = &quot;com.xxx.security.springmvc&quot;</span><br><span class="hljs-meta">            ,excludeFilters = &#123;@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)&#125;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ApplicationConfig</span> </span>&#123;<br>    <span class="hljs-comment">//在此配置除了Controller的其它bean，比如：数据库链接池、事务管理器、业务bean等。</span><br>&#125;<br></code></pre></div></td></tr></table></figure>
<h4 id="2-1-3-servletContext配置"><a href="#2-1-3-servletContext配置" class="headerlink" title="2.1.3 servletContext配置"></a>2.1.3 servletContext配置</h4><ul>
<li>config包下定义 <code>WebConfig</code> ，对应<code>DispatcherServlet</code>配置。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Configuration</span><span class="hljs-comment">//就相当于springmvc.xml文件</span><br><span class="hljs-meta">@EnableWebMvc</span> <span class="hljs-comment">// 接管 MVC</span><br><span class="hljs-meta">@ComponentScan(basePackages = &quot;com.xxx.security.springmvc&quot;</span><br><span class="hljs-meta">        ,includeFilters = &#123;@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)&#125;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebConfig</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">WebMvcConfigurer</span> </span>&#123;	<br>    <span class="hljs-comment">//视图解析器</span><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> InternalResourceViewResolver <span class="hljs-title">viewResolver</span><span class="hljs-params">()</span> </span>&#123;<br>        InternalResourceViewResolver viewResolver = <span class="hljs-keyword">new</span> InternalResourceViewResolver();<br>        viewResolver.setPrefix(<span class="hljs-string">&quot;/WEB-INF/view/&quot;</span>);<br>        viewResolver.setSuffix(<span class="hljs-string">&quot;.jsp&quot;</span>); <span class="hljs-comment">// 用jsp来演示代码</span><br>        <span class="hljs-keyword">return</span> viewResolver;<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<h4 id="2-1-4-加载-Spring容器"><a href="#2-1-4-加载-Spring容器" class="headerlink" title="2.1.4 加载 Spring容器"></a>2.1.4 加载 Spring容器</h4><ul>
<li>在init包下定义Spring容器初始化类<code>SpringApplicationInitializer</code>，此类实现WebApplicationInitializer接口，Spring容器启动时加载WebApplicationInitializer接口的所有实现类。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SpringApplicationInitializer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AbstractAnnotationConfigDispatcherServletInitializer</span> </span>&#123;<br>    <span class="hljs-comment">//spring容器，相当于加载 applicationContext.xml</span><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">protected</span> Class&lt;?&gt;[] getRootConfigClasses() &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Class[]&#123;ApplicationConfig.class&#125;;<br>    &#125;<br><br>    <span class="hljs-comment">//servletContext，相当于加载springmvc.xml</span><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">protected</span> Class&lt;?&gt;[] getServletConfigClasses() &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Class[]&#123;WebConfig.class&#125;;<br>    &#125;<br><br>    <span class="hljs-comment">//url-mapping</span><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">protected</span> String[] getServletMappings() &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> String[]&#123;<span class="hljs-string">&quot;/&quot;</span>&#125;;<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210409165409689.png" srcset="/img/loading.gif" lazyload></p>
<p>SpringApplicationInitializer相当于web.xml，ApplicationConfig.java对应以下配置的application-context.xml，WebConfig.java对应以下配置的<strong>spring-mvc.xml</strong>，<strong>web.xml</strong>的内容参考：</p>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">&lt;web‐app&gt;<br>    &lt;listener&gt;<br>        &lt;listener‐<span class="hljs-class"><span class="hljs-keyword">class</span>&gt;<span class="hljs-title">org</span>.<span class="hljs-title">springframework</span>.<span class="hljs-title">web</span>.<span class="hljs-title">context</span>.<span class="hljs-title">ContextLoaderListener</span>&lt;/<span class="hljs-title">listener</span>‐<span class="hljs-title">class</span>&gt;</span><br><span class="hljs-class">    &lt;/<span class="hljs-title">listener</span>&gt;</span><br><span class="hljs-class">    &lt;<span class="hljs-title">context</span>‐<span class="hljs-title">param</span>&gt;</span><br><span class="hljs-class">        &lt;<span class="hljs-title">param</span>‐<span class="hljs-title">name</span>&gt;<span class="hljs-title">contextConfigLocation</span>&lt;/<span class="hljs-title">param</span>‐<span class="hljs-title">name</span>&gt;</span><br><span class="hljs-class">        &lt;<span class="hljs-title">param</span>‐<span class="hljs-title">value</span>&gt;/<span class="hljs-title">WEB</span>‐<span class="hljs-title">INF</span>/<span class="hljs-title">application</span>‐<span class="hljs-title">context</span>.<span class="hljs-title">xml</span>&lt;/<span class="hljs-title">param</span>‐<span class="hljs-title">value</span>&gt;</span><br><span class="hljs-class">    &lt;/<span class="hljs-title">context</span>‐<span class="hljs-title">param</span>&gt; </span><br><span class="hljs-class">    &lt;<span class="hljs-title">servlet</span>&gt;</span><br><span class="hljs-class">        &lt;<span class="hljs-title">servlet</span>‐<span class="hljs-title">name</span>&gt;<span class="hljs-title">springmvc</span>&lt;/<span class="hljs-title">servlet</span>‐<span class="hljs-title">name</span>&gt;</span><br><span class="hljs-class">        &lt;<span class="hljs-title">servlet</span>‐<span class="hljs-title">class</span>&gt;<span class="hljs-title">org</span>.<span class="hljs-title">springframework</span>.<span class="hljs-title">web</span>.<span class="hljs-title">servlet</span>.<span class="hljs-title">DispatcherServlet</span>&lt;/<span class="hljs-title">servlet</span>‐<span class="hljs-title">class</span>&gt;</span><br><span class="hljs-class">        &lt;<span class="hljs-title">init</span>‐<span class="hljs-title">param</span>&gt;</span><br><span class="hljs-class">            &lt;<span class="hljs-title">param</span>‐<span class="hljs-title">name</span>&gt;<span class="hljs-title">contextConfigLocation</span>&lt;/<span class="hljs-title">param</span>‐<span class="hljs-title">name</span>&gt;</span><br><span class="hljs-class">            &lt;<span class="hljs-title">param</span>‐<span class="hljs-title">value</span>&gt;/<span class="hljs-title">WEB</span>‐<span class="hljs-title">INF</span>/<span class="hljs-title">spring</span>‐<span class="hljs-title">mvc</span>.<span class="hljs-title">xml</span>&lt;/<span class="hljs-title">param</span>‐<span class="hljs-title">value</span>&gt;</span><br><span class="hljs-class">        &lt;/<span class="hljs-title">init</span>‐<span class="hljs-title">param</span>&gt;</span><br><span class="hljs-class">        &lt;<span class="hljs-title">load</span>‐<span class="hljs-title">on</span>‐<span class="hljs-title">startup</span>&gt;1&lt;/<span class="hljs-title">load</span>‐<span class="hljs-title">on</span>‐<span class="hljs-title">startup</span>&gt;</span><br><span class="hljs-class">    &lt;/<span class="hljs-title">servlet</span>&gt;</span><br><span class="hljs-class">    &lt;<span class="hljs-title">servlet</span>‐<span class="hljs-title">mapping</span>&gt;</span><br><span class="hljs-class">        &lt;<span class="hljs-title">servlet</span>‐<span class="hljs-title">name</span>&gt;<span class="hljs-title">springmvc</span>&lt;/<span class="hljs-title">servlet</span>‐<span class="hljs-title">name</span>&gt;</span><br><span class="hljs-class">        &lt;<span class="hljs-title">url</span>‐<span class="hljs-title">pattern</span>&gt;/&lt;/<span class="hljs-title">url</span>‐<span class="hljs-title">pattern</span>&gt;</span><br><span class="hljs-class">    &lt;/<span class="hljs-title">servlet</span>‐<span class="hljs-title">mapping</span>&gt;</span><br><span class="hljs-class">&lt;/<span class="hljs-title">web</span>‐<span class="hljs-title">app</span>&gt;</span><br></code></pre></div></td></tr></table></figure>
<h3 id="2-2-实现认证功能"><a href="#2-2-实现认证功能" class="headerlink" title="2.2 实现认证功能"></a>2.2 实现认证功能</h3><h4 id="2-2-1-认证页面"><a href="#2-2-1-认证页面" class="headerlink" title="2.2.1  认证页面"></a>2.2.1  认证页面</h4><ul>
<li>在<code>webapp/WEB-INF/views</code>下定义认证页面<code>login.jsp</code>，作为测试认证流程，页面为form表单，包括用户名，密码，触发登录将提交表单信息至<code>/login</code> 「controller」。</li>
</ul>
<figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs jsp">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF‐8&quot;</span> pageEncoding=<span class="hljs-string">&quot;utf‐8&quot;</span> %&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;用户登录&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>&lt;form action=<span class="hljs-string">&quot;login&quot;</span> method=<span class="hljs-string">&quot;post&quot;</span>&gt;<br>    用户名：&lt;input type=<span class="hljs-string">&quot;text&quot;</span> name=<span class="hljs-string">&quot;username&quot;</span>&gt;&lt;br&gt;<br>    密&amp;nbsp;&amp;nbsp;&amp;nbsp;码:<br>    &lt;input type=<span class="hljs-string">&quot;password&quot;</span> name=<span class="hljs-string">&quot;password&quot;</span>&gt;&lt;br&gt;<br>    &lt;input type=<span class="hljs-string">&quot;submit&quot;</span> value=<span class="hljs-string">&quot;登录&quot;</span>&gt;<br>&lt;/form&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>在WebConfig中新增如下配置，将/直接导向login.jsp页面</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Override</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addViewControllers</span><span class="hljs-params">(ViewControllerRegistry registry)</span> </span>&#123;<br>    registry.addViewController(<span class="hljs-string">&quot;/&quot;</span>).setViewName(<span class="hljs-string">&quot;login&quot;</span>);<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>使用tomcat7插件运行测试，配置如下</li>
</ul>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210409170358793.png" srcset="/img/loading.gif" lazyload></p>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210409170436346.png" srcset="/img/loading.gif" lazyload></p>
<hr>
<h4 id="2-2-2-认证接口"><a href="#2-2-2-认证接口" class="headerlink" title="2.2.2 认证接口"></a>2.2.2 认证接口</h4><ol>
<li>定义认证接口，此接口对传来的用户名密码校验，若成功则返回该用户的详细信息，否则抛出错误异常</li>
</ol>
<ul>
<li>在service包下创建<code>AuthenticationService</code>接口</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">AuthenticationService</span> </span>&#123;<br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 用户认证</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> authenticationRequest 用户认证请求，账号和密码</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 认证成功的用户信息</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-function">UserDto <span class="hljs-title">authentication</span><span class="hljs-params">(AuthenticationRequest authenticationRequest)</span></span>;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>model包下，认证请求结构</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Data</span> <span class="hljs-comment">// import lombok.Data;</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthenticationRequest</span> </span>&#123;<br>    <span class="hljs-comment">//认证请求参数，账号、密码</span><br>    <span class="hljs-keyword">private</span> String username;<br>    <span class="hljs-keyword">private</span> String password;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>model包下，创建UerDto，作为登录成功后获得的登录用户的信息</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Data</span><br><span class="hljs-meta">@AllArgsConstructor</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserDto</span> </span>&#123;<br>    <span class="hljs-comment">//用户身份信息</span><br>    <span class="hljs-keyword">private</span> String id;<br>    <span class="hljs-keyword">private</span> String username;<br>    <span class="hljs-keyword">private</span> String password;<br>    <span class="hljs-keyword">private</span> String fullname;<br>    <span class="hljs-keyword">private</span> String mobile;<br>    <span class="hljs-keyword">private</span> Set&lt;String&gt; authorities; <span class="hljs-comment">// 用户权限用Set集合存储</span><br>&#125;<br></code></pre></div></td></tr></table></figure>
<ol start="2">
<li>认证实现类，根据用户名查找用户信息，并校验密码。</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Service</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthenticationServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">AuthenticationService</span> </span>&#123;<br>    <span class="hljs-comment">//匿名代码块，初始化数据，模拟数据库</span><br>    &#123;<br>        Set&lt;String&gt; authorities1 = <span class="hljs-keyword">new</span> HashSet&lt;&gt;();<br>        authorities1.add(<span class="hljs-string">&quot;p1&quot;</span>);<span class="hljs-comment">// p1和/r/r1对应,后面controller会用到</span><br>        Set&lt;String&gt; authorities2 = <span class="hljs-keyword">new</span> HashSet&lt;&gt;();<br>        authorities2.add(<span class="hljs-string">&quot;p2&quot;</span>);<span class="hljs-comment">// p2和/r/r2对应,后面controller会用到</span><br>        userMap.put(<span class="hljs-string">&quot;zhangsan&quot;</span>, <span class="hljs-keyword">new</span> UserDto(<span class="hljs-string">&quot;1010&quot;</span>, <span class="hljs-string">&quot;zhangsan&quot;</span>, <span class="hljs-string">&quot;123&quot;</span>, <span class="hljs-string">&quot;张三&quot;</span>, <span class="hljs-string">&quot;133443&quot;</span>, authorities1));<br>        userMap.put(<span class="hljs-string">&quot;lisi&quot;</span>, <span class="hljs-keyword">new</span> UserDto(<span class="hljs-string">&quot;1011&quot;</span>, <span class="hljs-string">&quot;lisi&quot;</span>, <span class="hljs-string">&quot;456&quot;</span>, <span class="hljs-string">&quot;李四&quot;</span>, <span class="hljs-string">&quot;144553&quot;</span>, authorities2));<br>    &#125;<br>    <br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 用户认证，校验用户身份信息是否合法</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> authenticationRequest 用户认证请求，账号和密码</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 认证成功的用户信息</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> UserDto <span class="hljs-title">authentication</span><span class="hljs-params">(AuthenticationRequest authenticationRequest)</span> </span>&#123;<br>        <span class="hljs-comment">//校验参数是否为空</span><br>        <span class="hljs-keyword">if</span> (authenticationRequest == <span class="hljs-keyword">null</span><br>                || StringUtils.isEmpty(authenticationRequest.getUsername())<br>                || StringUtils.isEmpty(authenticationRequest.getPassword())) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">&quot;账号和密码为空&quot;</span>);<br>        &#125;<br>        <span class="hljs-comment">//根据账号去查询数据库,这里测试程序采用模拟方法</span><br>        UserDto user = getUserDto(authenticationRequest.getUsername());<br>        <span class="hljs-comment">//判断用户是否为空</span><br>        <span class="hljs-keyword">if</span> (user == <span class="hljs-keyword">null</span>) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">&quot;查询不到该用户&quot;</span>);<br>        &#125;<br>        <span class="hljs-comment">//校验密码</span><br>        <span class="hljs-keyword">if</span> (!authenticationRequest.getPassword().equals(user.getPassword())) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">&quot;账号或密码错误&quot;</span>);<br>        &#125;<br>        <span class="hljs-comment">//认证通过，返回用户身份信息</span><br>        <span class="hljs-keyword">return</span> user;<br>    &#125;<br><br>    <span class="hljs-comment">//根据账号查询用户信息</span><br>    <span class="hljs-function"><span class="hljs-keyword">private</span> UserDto <span class="hljs-title">getUserDto</span><span class="hljs-params">(String userName)</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> userMap.get(userName);<br>    &#125;<br><br>    <span class="hljs-comment">//用户信息</span><br>    <span class="hljs-keyword">private</span> Map&lt;String, UserDto&gt; userMap = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ol start="3">
<li>登录Controller，对/login请求处理，它调用AuthenticationService完成认证并返回登录结果提示信息：</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@RestController</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoginController</span> </span>&#123;<br>    <span class="hljs-meta">@Autowired</span><br>    AuthenticationService authenticationService;<br><br>    <span class="hljs-meta">@RequestMapping(value = &quot;/login&quot;, produces = &#123;&quot;text/plain;charset=UTF-8&quot;&#125;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">login</span><span class="hljs-params">(AuthenticationRequest authenticationRequest, HttpSession session)</span> </span>&#123;<br>        UserDto userDto = authenticationService.authentication(authenticationRequest);<br>        <span class="hljs-keyword">return</span> userDto.getUsername() + <span class="hljs-string">&quot;登录成功&quot;</span>;<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ol start="4">
<li>Test，访问路径为 /</li>
</ol>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210409173720669.png" srcset="/img/loading.gif" lazyload></p>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210409173731950.png" srcset="/img/loading.gif" lazyload></p>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210409173748505.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li>至此，完成最简单的身份凭证校验，后面对于资源的请求还要单独授权。</li>
</ul>
<h4 id="2-2-3-实现会话功能"><a href="#2-2-3-实现会话功能" class="headerlink" title="2.2.3 实现会话功能"></a>2.2.3 实现会话功能</h4><ol>
<li>增加会话控制</li>
</ol>
<ul>
<li>在UserDto中定义一个SESSION_USER_KEY，作为Session中存放登录用户信息的key</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String SESSION_USER_KEY = <span class="hljs-string">&quot;_user&quot;</span>;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>修改LoginController，认证成功后，将用户信息放入当前会话。并增加用户登出方法，登出时将session置为<br>失效。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@RequestMapping(value = &quot;/login&quot;, produces = &#123;&quot;text/plain;charset=UTF-8&quot;&#125;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">login</span><span class="hljs-params">(AuthenticationRequest authenticationRequest, HttpSession session)</span> </span>&#123;<br>    UserDto userDto = authenticationService.authentication(authenticationRequest);<br>    <span class="hljs-comment">//存入session</span><br>    session.setAttribute(UserDto.SESSION_USER_KEY, userDto);<br>    <span class="hljs-keyword">return</span> userDto.getUsername() + <span class="hljs-string">&quot;登录成功&quot;</span>;<br>&#125;<br><br><span class="hljs-meta">@GetMapping(value = &quot;/logout&quot;, produces = &#123;&quot;text/plain;charset=UTF-8&quot;&#125;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">logout</span><span class="hljs-params">(HttpSession session)</span> </span>&#123;<br>    session.invalidate(); <span class="hljs-comment">// 将session非法化就达到退出效果</span><br>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;退出成功&quot;</span>;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ol start="2">
<li>增加测试资源</li>
</ol>
<ul>
<li>修改LoginController，增加测试r1，它从当前会话session中获取当前登录用户，并返回提示信息给前台。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@GetMapping(value = &quot;/r/r1&quot;, produces = &#123;&quot;text/plain;charset=UTF-8&quot;&#125;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">r1</span><span class="hljs-params">(HttpSession session)</span> </span>&#123;<br>    String fullname = <span class="hljs-keyword">null</span>;<br>    Object object = session.getAttribute(UserDto.SESSION_USER_KEY);<br>    <span class="hljs-keyword">if</span> (object == <span class="hljs-keyword">null</span>) &#123;<br>        fullname = <span class="hljs-string">&quot;匿名&quot;</span>;<br>    &#125; <span class="hljs-keyword">else</span> &#123;<br>        UserDto userDto = (UserDto) object;<br>        fullname = userDto.getFullname();<br>    &#125;<br>    <span class="hljs-keyword">return</span> fullname + <span class="hljs-string">&quot;访问资源r1&quot;</span>;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ol start="3">
<li>Test</li>
</ol>
<ul>
<li>未登录情况下直接访问测试资源/r/r1</li>
</ul>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210410114837028.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li>成功登录的情况下访问测试资源/r/r1</li>
</ul>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210410114851102.png" srcset="/img/loading.gif" lazyload></p>
<p>在用户登录成功时，该用户信息已被成功放入session，并且后续请求可以正常从session中获取当<br>前登录用户信息，符合预期结果。</p>
<hr>
<h4 id="2-2-4-实现授权功能"><a href="#2-2-4-实现授权功能" class="headerlink" title="2.2.4 实现授权功能"></a>2.2.4 实现授权功能</h4><ul>
<li>匿名用户（未登录用户）访问拦截：禁止匿名用户访问某些资源。</li>
<li>登录用户访问拦截：根据用户的<strong>权限</strong>决定是否能访问某些资源。</li>
</ul>
<ol>
<li>增加权限数据</li>
</ol>
<ul>
<li>UserDto添加用户权限，用Set集合存储</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">private</span> Set&lt;String&gt; authorities;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>在AuthenticationServiceImpl中为模拟用户初始化权限，其中张三给了p1权限，李四给了p2权限。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"> 	<span class="hljs-comment">//用户信息</span><br>    <span class="hljs-keyword">private</span> Map&lt;String,UserDto&gt; userMap = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();<br>    &#123;<br>        Set&lt;String&gt; authorities1 = <span class="hljs-keyword">new</span> HashSet&lt;&gt;();<br>        authorities1.add(<span class="hljs-string">&quot;p1&quot;</span>);<br>        Set&lt;String&gt; authorities2 = <span class="hljs-keyword">new</span> HashSet&lt;&gt;();<br>        authorities2.add(<span class="hljs-string">&quot;p2&quot;</span>);<br>        userMap.put(<span class="hljs-string">&quot;zhangsan&quot;</span>,<span class="hljs-keyword">new</span> UserDto(<span class="hljs-string">&quot;1010&quot;</span>,<span class="hljs-string">&quot;zhangsan&quot;</span>,<span class="hljs-string">&quot;123&quot;</span>,<span class="hljs-string">&quot;张</span><br><span class="hljs-string">三&quot;</span>,<span class="hljs-string">&quot;133443&quot;</span>,authorities1));<br>        userMap.put(<span class="hljs-string">&quot;lisi&quot;</span>,<span class="hljs-keyword">new</span> UserDto(<span class="hljs-string">&quot;1011&quot;</span>,<span class="hljs-string">&quot;lisi&quot;</span>,<span class="hljs-string">&quot;456&quot;</span>,<span class="hljs-string">&quot;李四&quot;</span>,<span class="hljs-string">&quot;144553&quot;</span>,authorities2));<br>    &#125;<br></code></pre></div></td></tr></table></figure>
<ol start="2">
<li>增加测试资源，同/r/r1，这是资源r2</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@GetMapping(value = &quot;/r/r2&quot;, produces = &#123;&quot;text/plain;charset=UTF-8&quot;&#125;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">r2</span><span class="hljs-params">(HttpSession session)</span> </span>&#123;<br>    String fullname = <span class="hljs-keyword">null</span>;<br>    Object userObj = session.getAttribute(UserDto.SESSION_USER_KEY);<br>    <span class="hljs-keyword">if</span> (userObj != <span class="hljs-keyword">null</span>) &#123;<br>        fullname = ((UserDto) userObj).getFullname();<br>    &#125; <span class="hljs-keyword">else</span> &#123;<br>        fullname = <span class="hljs-string">&quot;匿名&quot;</span>;<br>    &#125;<br>    <span class="hljs-keyword">return</span> fullname + <span class="hljs-string">&quot; 访问资源r2&quot;</span>;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ol start="3">
<li>实现授权拦截器</li>
</ol>
<ul>
<li>在<code>interceptor</code>包下定义<code>SimpleAuthenticationInterceptor</code>拦截器</li>
<li>实现 1、校验用户是否登录 2、校验用户是否拥有操作权限</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Component</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SimpleAuthenticationInterceptor</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">HandlerInterceptor</span> </span>&#123;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">preHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        <span class="hljs-comment">//在这个方法中校验用户请求的url是否在用户的权限范围内</span><br>        <span class="hljs-comment">//取出用户身份信息</span><br>        Object object = request.getSession().getAttribute(UserDto.SESSION_USER_KEY);<br>        <span class="hljs-keyword">if</span> (object == <span class="hljs-keyword">null</span>) &#123;<br>            <span class="hljs-comment">//没有认证，提示登录</span><br>            writeContent(response, <span class="hljs-string">&quot;请登录&quot;</span>);<br>        &#125;<br>        UserDto userDto = (UserDto) object;<br>        <span class="hljs-comment">//请求的url</span><br>        String requestURI = request.getRequestURI();<br>        <span class="hljs-keyword">if</span> (userDto.getAuthorities().contains(<span class="hljs-string">&quot;p1&quot;</span>) &amp;&amp; requestURI.contains(<span class="hljs-string">&quot;/r/r1&quot;</span>)) &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;<br>        &#125;<br>        <span class="hljs-keyword">if</span> (userDto.getAuthorities().contains(<span class="hljs-string">&quot;p2&quot;</span>) &amp;&amp; requestURI.contains(<span class="hljs-string">&quot;/r/r2&quot;</span>)) &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;<br>        &#125;<br>        writeContent(response, <span class="hljs-string">&quot;没有权限，拒绝访问&quot;</span>);<br><br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;<br>    &#125;<br><br>    <span class="hljs-comment">//响应信息给客户端</span><br>    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">writeContent</span><span class="hljs-params">(HttpServletResponse response, String msg)</span> <span class="hljs-keyword">throws</span> IOException </span>&#123;<br>        response.setContentType(<span class="hljs-string">&quot;text/html;charset=utf-8&quot;</span>);<br>        PrintWriter writer = response.getWriter();<br>        writer.print(msg);<br>        writer.close();<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>在 WebConfig中配置拦截器，匹配<code>/r/**</code>的资源为受保护的系统资源，访问该资源的请求进入<br>SimpleAuthenticationInterceptor拦截器。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Autowired</span><br><span class="hljs-keyword">private</span> SimpleAuthenticationInterceptor simpleAuthenticationInterceptor;<br>   <br><span class="hljs-meta">@Override</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addInterceptors</span><span class="hljs-params">(InterceptorRegistry registry)</span> </span>&#123;<br>    registry.addInterceptor(simpleAuthenticationInterceptor).addPathPatterns(<span class="hljs-string">&quot;/r/**&quot;</span>);<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ol start="4">
<li>Test</li>
</ol>
<ul>
<li>未登录</li>
</ul>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210410120022280.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li>张三登录</li>
</ul>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210410120052995.png" srcset="/img/loading.gif" lazyload></p>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210410120104477.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li>李四同理，只能访问r2。r1没有权限访问。</li>
</ul>
<h2 id="3-Spring-Security-快速上手「基于MVC」"><a href="#3-Spring-Security-快速上手「基于MVC」" class="headerlink" title="3. Spring Security 快速上手「基于MVC」"></a>3. Spring Security 快速上手「基于MVC」</h2><ul>
<li>Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。由于它是Spring生态系统中的一员，因此它伴随着整个Spring生态系统不断修正、升级，在spring boot项目中加入Spring Security更是十分简单，使用Spring Security减少了为企业系统安全控制编写大量重复代码的工作。</li>
</ul>
<h3 id="3-1-环境搭建"><a href="#3-1-环境搭建" class="headerlink" title="3.1 环境搭建"></a>3.1 环境搭建</h3><h4 id="3-1-1-创建Maven工程"><a href="#3-1-1-创建Maven工程" class="headerlink" title="3.1.1 创建Maven工程"></a>3.1.1 创建Maven工程</h4><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.itheima.security<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>security-spring-security<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.0-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">packaging</span>&gt;</span>war<span class="hljs-tag">&lt;/<span class="hljs-name">packaging</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">properties</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">project.build.sourceEncoding</span>&gt;</span>UTF-8<span class="hljs-tag">&lt;/<span class="hljs-name">project.build.sourceEncoding</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">maven.compiler.source</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">maven.compiler.source</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">maven.compiler.target</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">maven.compiler.target</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">properties</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- spring-security依赖 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.security<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-security-web<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.1.4.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.security<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-security-config<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.1.4.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-webmvc<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.1.5.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 不添加该依赖tomcat7:run无法运行项目 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>javax.servlet<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>javax.servlet-api<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.0.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>provided<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.projectlombok<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>lombok<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.18.8<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">build</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">finalName</span>&gt;</span>security-springmvc<span class="hljs-tag">&lt;/<span class="hljs-name">finalName</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">pluginManagement</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">plugins</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.tomcat.maven<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>tomcat7-maven-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>maven-compiler-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">source</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">source</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">target</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">target</span>&gt;</span><br>                <span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span><br><br>            <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>maven-resources-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">encoding</span>&gt;</span>utf-8<span class="hljs-tag">&lt;/<span class="hljs-name">encoding</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">useDefaultDelimiters</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">useDefaultDelimiters</span>&gt;</span><br>                    <span class="hljs-tag">&lt;<span class="hljs-name">resources</span>&gt;</span><br>                        <span class="hljs-tag">&lt;<span class="hljs-name">resource</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">directory</span>&gt;</span>src/main/resources<span class="hljs-tag">&lt;/<span class="hljs-name">directory</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">filtering</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">filtering</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">includes</span>&gt;</span><br>                                <span class="hljs-tag">&lt;<span class="hljs-name">include</span>&gt;</span>**/*<span class="hljs-tag">&lt;/<span class="hljs-name">include</span>&gt;</span><br>                            <span class="hljs-tag">&lt;/<span class="hljs-name">includes</span>&gt;</span><br>                        <span class="hljs-tag">&lt;/<span class="hljs-name">resource</span>&gt;</span><br>                        <span class="hljs-tag">&lt;<span class="hljs-name">resource</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">directory</span>&gt;</span>src/main/java<span class="hljs-tag">&lt;/<span class="hljs-name">directory</span>&gt;</span><br>                            <span class="hljs-tag">&lt;<span class="hljs-name">includes</span>&gt;</span><br>                                <span class="hljs-tag">&lt;<span class="hljs-name">include</span>&gt;</span>**/*.xml<span class="hljs-tag">&lt;/<span class="hljs-name">include</span>&gt;</span><br>                            <span class="hljs-tag">&lt;/<span class="hljs-name">includes</span>&gt;</span><br>                        <span class="hljs-tag">&lt;/<span class="hljs-name">resource</span>&gt;</span><br>                    <span class="hljs-tag">&lt;/<span class="hljs-name">resources</span>&gt;</span><br>                <span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">plugins</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">pluginManagement</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">build</span>&gt;</span><br></code></pre></div></td></tr></table></figure>
<h4 id="3-1-2-Spring容器配置"><a href="#3-1-2-Spring容器配置" class="headerlink" title="3.1.2 Spring容器配置"></a>3.1.2 Spring容器配置</h4><ul>
<li>同security-springmvc</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Configuration</span><br><span class="hljs-meta">@ComponentScan(basePackages = &quot;com.xxx.security.springmvc&quot;</span><br><span class="hljs-meta">                ,excludeFilters = &#123;@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)&#125;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ApplicationConfig</span> </span>&#123;<br>    <span class="hljs-comment">//在此配置除了Controller的其它bean，比如：数据库链接池、事务管理器、业务bean等。</span><br>&#125;<br></code></pre></div></td></tr></table></figure>
<h4 id="3-1-3-Servlet-Context配置"><a href="#3-1-3-Servlet-Context配置" class="headerlink" title="3.1.3 Servlet Context配置"></a>3.1.3 Servlet Context配置</h4><ul>
<li>同security-springmvc</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Configuration</span><br><span class="hljs-meta">@EnableWebMvc</span><br><span class="hljs-meta">@ComponentScan(basePackages = &quot;com.xxx.security.springmvc&quot;</span><br><span class="hljs-meta">            ,includeFilters = &#123;@ComponentScan.Filter(type = FilterType.ANNOTATION,value =</span><br><span class="hljs-meta">Controller.class)&#125;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebConfig</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">WebMvcConfigurer</span> </span>&#123;<br>    <span class="hljs-comment">//视频解析器</span><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> InternalResourceViewResolver <span class="hljs-title">viewResolver</span><span class="hljs-params">()</span></span>&#123;<br>        InternalResourceViewResolver viewResolver = <span class="hljs-keyword">new</span> InternalResourceViewResolver();<br>        viewResolver.setPrefix(<span class="hljs-string">&quot;/WEB‐INF/views/&quot;</span>);<br>        viewResolver.setSuffix(<span class="hljs-string">&quot;.jsp&quot;</span>);<br>        <span class="hljs-keyword">return</span> viewResolver;<br>    &#125;<br> &#125;<br></code></pre></div></td></tr></table></figure>
<h4 id="3-1-4-加载-Spring容器"><a href="#3-1-4-加载-Spring容器" class="headerlink" title="3.1.4  加载 Spring容器"></a>3.1.4  加载 Spring容器</h4><ul>
<li>在<code>init</code>包下定义Spring容器初始化类<code>SpringApplicationInitializer</code>，此类实现WebApplicationInitializer接口，Spring容器启动时加载WebApplicationInitializer接口的所有实现类。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SpringApplicationInitializer</span> <span class="hljs-keyword">extends</span></span><br><span class="hljs-class"><span class="hljs-title">AbstractAnnotationConfigDispatcherServletInitializer</span> </span>&#123;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">protected</span> Class&lt;?&gt;[] getRootConfigClasses() &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Class&lt;?&gt;[] &#123; ApplicationConfig.class &#125;;<span class="hljs-comment">//指定rootContext的配置类</span><br>    &#125;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">protected</span> Class&lt;?&gt;[] getServletConfigClasses() &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Class&lt;?&gt;[] &#123; WebConfig.class &#125;; <span class="hljs-comment">//指定servletContext的配置类</span><br>    &#125;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">protected</span> String[] getServletMappings() &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> String [] &#123;<span class="hljs-string">&quot;/&quot;</span>&#125;;<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<hr>
<h3 id="3-2-认证"><a href="#3-2-认证" class="headerlink" title="3.2 认证"></a>3.2 认证</h3><h4 id="3-2-1-认证页面"><a href="#3-2-1-认证页面" class="headerlink" title="3.2.1 认证页面"></a>3.2.1 认证页面</h4><ul>
<li>Spring Security默认提供认证页面，不需要额外开发。</li>
</ul>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210410162825759.png" srcset="/img/loading.gif" lazyload></p>
<h4 id="3-2-2-安全配置"><a href="#3-2-2-安全配置" class="headerlink" title="3.2.2 安全配置"></a>3.2.2 安全配置</h4><ul>
<li>Spring Security提供了<strong>用户名密码登录</strong>、<strong>退出</strong>、<strong>会话管理</strong>等认证功能，只需要配置即可使用。</li>
</ul>
<ol>
<li>在config包下定义<code>WebSecurityConfig</code>，作为Security框架的配置类，安全配置的内容包括：用户信息、密码编码器、安全拦截机制。</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@EnableWebSecurity</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebSecurityConfig</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">WebSecurityConfigurerAdapter</span> </span>&#123;<br>    <span class="hljs-comment">//定义用户信息服务（查询用户信息）</span><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> UserDetailsService <span class="hljs-title">userDetailsService</span><span class="hljs-params">()</span> </span>&#123;<br>        InMemoryUserDetailsManager manager = <span class="hljs-keyword">new</span> InMemoryUserDetailsManager();<br>        manager.createUser(User.withUsername(<span class="hljs-string">&quot;zhangsan&quot;</span>).password(<span class="hljs-string">&quot;123&quot;</span>).authorities(<span class="hljs-string">&quot;p1&quot;</span>).build());<br>        manager.createUser(User.withUsername(<span class="hljs-string">&quot;lisi&quot;</span>).password(<span class="hljs-string">&quot;456&quot;</span>).authorities(<span class="hljs-string">&quot;p2&quot;</span>).build());<br>        <span class="hljs-keyword">return</span> manager;<br>    &#125;<br><br>    <span class="hljs-comment">//密码编码器</span><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> PasswordEncoder <span class="hljs-title">passwordEncoder</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> NoOpPasswordEncoder.getInstance();<br>    &#125;<br><br>    <span class="hljs-comment">//安全拦截机制（最重要）</span><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configure</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        http.authorizeRequests()<br>                .antMatchers(<span class="hljs-string">&quot;/r/r1&quot;</span>).hasAuthority(<span class="hljs-string">&quot;p1&quot;</span>)<br>                .antMatchers(<span class="hljs-string">&quot;/r/r2&quot;</span>).hasAuthority(<span class="hljs-string">&quot;p2&quot;</span>)<br>                .antMatchers(<span class="hljs-string">&quot;/r/**&quot;</span>).authenticated() <span class="hljs-comment">// 所有/r/**的请求必须认证通过</span><br>                .anyRequest().permitAll()   <span class="hljs-comment">// 除了/r/**，其它的请求可以访问</span><br>                .and()<br>                .formLogin() <span class="hljs-comment">// 允许表单登录</span><br>                .successForwardUrl(<span class="hljs-string">&quot;/login-success&quot;</span>); <span class="hljs-comment">// 自定义登录成功的页面地址</span><br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<p>需要说明的是：</p>
<ul>
<li><code>@EnableWebSecurity</code>注解已经包含了 <code>@Configuration</code></li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Import(&#123; WebSecurityConfiguration.class,</span><br><span class="hljs-meta">      SpringWebMvcImportSelector.class,</span><br><span class="hljs-meta">      OAuth2ImportSelector.class &#125;)</span><br><span class="hljs-meta">@EnableGlobalAuthentication</span><br><span class="hljs-meta">@Configuration</span><br><span class="hljs-keyword">public</span> <span class="hljs-meta">@interface</span> EnableWebSecurity &#123;...&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>在 <code>userDetailsService() </code>方法中，返回一个UserDetailsService 给 Spring容S器，Spring Security会使用它来<br>获取用户信息。暂时使用InMemoryUserDetailsManager实现类，并在其中分别创建了zhangsan、lisi两个用<br>户，并设置密码和权限。<code>InMemoryUserDetailsManager</code>是 <code>UserDetailsService </code>接口实现类。</li>
</ul>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210410163409717.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li>在configure()中，通过HttpSecurity设置了安全拦截规则<ul>
<li>1️⃣url匹配<code>/r/**</code>的资源，经过认证后才能访问</li>
<li>2️⃣其他url完全开放</li>
<li>3️⃣支持form表单认证，认证成功后转向<code>/login-success</code></li>
</ul>
</li>
</ul>
<ol start="2">
<li>加载 WebSecurityConfig</li>
</ol>
<ul>
<li>修改<code>SpringApplicationInitializer</code>的<code>getRootConfigClasses()</code>方法，添加 <code>WebSecurityConfig.class</code></li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Override</span><br><span class="hljs-keyword">protected</span> Class&lt;?&gt;[] getRootConfigClasses() &#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Class&lt;?&gt;[] &#123; ApplicationConfig.class, WebSecurityConfig.class&#125;;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<h4 id="3-2-3-Spring-Security初始化"><a href="#3-2-3-Spring-Security初始化" class="headerlink" title="3.2.3 Spring Security初始化"></a>3.2.3 Spring Security初始化</h4><ul>
<li><p>Spring Security 初始化，有两种情况</p>
<ul>
<li>若当前环境没有使用 Spring 或 Spring MVC，则需要将 WebSecurityConfig(Spring Security配置类) 传入超<br>类，以确保获取配置，并创建spring context。</li>
<li>相反，若当前环境<strong>已经使用 Spring</strong>，我们应该在现有的SpringContext中注册Spring Security「上一步已经做将WebSecurityConfig加载至rootcontext」，此方法可以什么都不做。</li>
</ul>
</li>
<li><p>在<code>init</code>包下定义<code>SpringSecurityApplicationInitializer</code></p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SpringSecurityApplicationInitializer</span></span><br><span class="hljs-class">        <span class="hljs-keyword">extends</span> <span class="hljs-title">AbstractSecurityWebApplicationInitializer</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">SpringSecurityApplicationInitializer</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-comment">//super(WebSecurityConfig.class);</span><br>        <span class="hljs-comment">//没有使用Spring或Spring MVC，则需要将WebSecurityConfig(Spring Security配置类) 传入超</span><br>        <span class="hljs-comment">//类，以确保获取配置，并创建spring context。</span><br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<h4 id="3-2-4-默认根路径请求"><a href="#3-2-4-默认根路径请求" class="headerlink" title="3.2.4 默认根路径请求"></a>3.2.4 默认根路径请求</h4><ul>
<li>在WebConfig.java中添加默认请求根路径跳转到<code>/login</code>，此url为<strong>Spring Security</strong>提供：</li>
<li>这里要用重定向到默认的 /login 界面</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-comment">// 默认Url根路径跳转到/login，此url为spring security提供</span><br><span class="hljs-meta">@Override</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addViewControllers</span><span class="hljs-params">(ViewControllerRegistry registry)</span> </span>&#123;<br>    registry.addViewController(<span class="hljs-string">&quot;/&quot;</span>).setViewName(<span class="hljs-string">&quot;redirect:/login&quot;</span>);<br>&#125;<br></code></pre></div></td></tr></table></figure>
<h4 id="3-2-5-认证成功页面"><a href="#3-2-5-认证成功页面" class="headerlink" title="3.2.5 认证成功页面"></a>3.2.5 认证成功页面</h4><ul>
<li>在安全配置中，认证成功将跳转到<code>/login-success</code></li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-comment">//安全拦截机制（最重要）</span><br><span class="hljs-meta">@Override</span><br><span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configure</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>    http.authorizeRequests()<br>        .antMatchers(<span class="hljs-string">&quot;/r/r1&quot;</span>).hasAuthority(<span class="hljs-string">&quot;p1&quot;</span>)<br>        .antMatchers(<span class="hljs-string">&quot;/r/r2&quot;</span>).hasAuthority(<span class="hljs-string">&quot;p2&quot;</span>)<br>        .antMatchers(<span class="hljs-string">&quot;/r/**&quot;</span>).authenticated() <span class="hljs-comment">// 所有/r/**的请求必须认证通过</span><br>        .anyRequest().permitAll()   <span class="hljs-comment">// 除了/r/**，其它的请求可以访问</span><br>        .and()<br>        .formLogin() <span class="hljs-comment">// 允许表单登录</span><br>        .successForwardUrl(<span class="hljs-string">&quot;/login-success&quot;</span>); <span class="hljs-comment">// 自定义登录成功的页面地址</span><br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>Spring Security支持form表单认证，认证成功后转向<code>/login-success</code>。</li>
<li>在<code>LoginController</code>中定义<code>/login-success</code></li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@RequestMapping(value = &quot;/login‐success&quot;,produces = &#123;&quot;text/plain;charset=UTF‐8&quot;&#125;)</span> <br><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">loginSuccess</span><span class="hljs-params">()</span></span>&#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot; 登录成功&quot;</span>;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<h4 id="3-2-6-Test"><a href="#3-2-6-Test" class="headerlink" title="3.2.6 Test"></a>3.2.6 Test</h4><ol>
<li>启动项目，访问<a target="_blank" rel="noopener" href="http://localhost:8080/security-spring-security/%E8%B7%AF%E5%BE%84%E5%9C%B0%E5%9D%80">http://localhost:8080/security-spring-security/路径地址</a></li>
</ol>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210410165535635.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li>页面会根据WebConfig中addViewControllers配置规则，重定向跳转至/login，/login是pring Security提供的登录页面。</li>
</ul>
<ol start="2">
<li>登录</li>
</ol>
<ul>
<li>账户名、密码错误</li>
</ul>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210410165724178.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li>账户名：zhangsan；密码：123</li>
</ul>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210410165809551.png" srcset="/img/loading.gif" lazyload></p>
<ol start="3">
<li>输入<a target="_blank" rel="noopener" href="http://localhost:8080/security-spring-security/logout%E9%80%80%E5%87%BA%EF%BC%8CLog">http://localhost:8080/security-spring-security/logout退出，Log</a> Out自动跳转回登录界面</li>
</ol>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210410165846215.png" srcset="/img/loading.gif" lazyload></p>
<hr>
<h3 id="3-3-授权"><a href="#3-3-授权" class="headerlink" title="3.3 授权"></a>3.3 授权</h3><ul>
<li><p>实现授权需要对用户的访问进行拦截校验，校验用户的权限是否可以操作指定的资源，Spring Security默认提供授权实现方法。</p>
</li>
<li><p>在<code>LoginController</code>添加<code>/r/r1</code>或<code>/r/r2</code></p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-comment">// 测试资源1</span><br><span class="hljs-meta">@GetMapping(value = &quot;/r/r1&quot;, produces = &#123;&quot;text/plain;charset=UTF-8&quot;&#125;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">r1</span><span class="hljs-params">()</span> </span>&#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot; 访问资源1&quot;</span>;<br>&#125;<br><br><span class="hljs-comment">// 测试资源2</span><br><span class="hljs-meta">@GetMapping(value = &quot;/r/r2&quot;, produces = &#123;&quot;text/plain;charset=UTF-8&quot;&#125;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">r2</span><span class="hljs-params">()</span> </span>&#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot; 访问资源2&quot;</span>;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>之前给两个测试用户绑定了相应的权限，表示访问”/xxx”资源的url需要有”px”的权限</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">manager.createUser(User.withUsername(<span class="hljs-string">&quot;zhangsan&quot;</span>).password(<span class="hljs-string">&quot;123&quot;</span>).authorities(<span class="hljs-string">&quot;p1&quot;</span>).build());<br>manager.createUser(User.withUsername(<span class="hljs-string">&quot;lisi&quot;</span>).password(<span class="hljs-string">&quot;456&quot;</span>).authorities(<span class="hljs-string">&quot;p2&quot;</span>).build()); <br><span class="hljs-comment">// protected void configure(HttpSecurity http) ↓↓↓↓</span><br>.antMatchers(<span class="hljs-string">&quot;/r/r1&quot;</span>).hasAuthority(<span class="hljs-string">&quot;p1&quot;</span>)                                       <br>.antMatchers(<span class="hljs-string">&quot;/r/r2&quot;</span>).hasAuthority(<span class="hljs-string">&quot;p2&quot;</span>)<br></code></pre></div></td></tr></table></figure>
<ul>
<li>Test</li>
</ul>
<ol>
<li><p>张三登录，访问r1资源</p>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210410170553915.png" srcset="/img/loading.gif" lazyload></p>
</li>
<li><p>张三访问r2资源，403无权限</p>
</li>
</ol>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210410170804126.png" srcset="/img/loading.gif" lazyload></p>
<h2 id="4-Spring-Security-基本原理"><a href="#4-Spring-Security-基本原理" class="headerlink" title="4 Spring Security  基本原理"></a>4 Spring Security  基本原理</h2><h3 id="4-1-Spring-Security本质"><a href="#4-1-Spring-Security本质" class="headerlink" title="4.1 Spring Security本质"></a>4.1 Spring Security本质</h3><ul>
<li>SpringSecurity 本质是一个<strong>过滤器链</strong>，从启动可以获取到过滤器链：<ul>
<li>org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFil<br>ter</li>
<li>org.springframework.security.web.context.SecurityContextPersistenceFilter</li>
<li>org.springframework.security.web.header.HeaderWriterFilter</li>
<li>org.springframework.security.web.csrf.CsrfFilter</li>
<li>org.springframework.security.web.authentication.logout.LogoutFilter</li>
<li>org.springframework.security.web.authentication.<code>UsernamePasswordAuthenticationFilter</code></li>
<li>org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter</li>
<li>org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter</li>
<li>org.springframework.security.web.savedrequest.RequestCacheAwareFilter</li>
<li>org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter</li>
<li>org.springframework.security.web.authentication.AnonymousAuthenticationFilter</li>
<li>org.springframework.security.web.session.SessionManagementFilter</li>
<li>org.springframework.security.web.access.<code>ExceptionTranslationFilter</code></li>
<li>org.springframework.security.web.access.intercept.<code>FilterSecurityInterceptor</code></li>
</ul>
</li>
</ul>
<p>重点看三个过滤器：</p>
<ol>
<li><code>FilterSecurityInterceptor</code></li>
</ol>
<p>一个<strong>方法级</strong>的权限过滤器, 基本位于过滤链的最底部。</p>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FilterSecurityInterceptor</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AbstractSecurityInterceptor</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Filter</span> </span>&#123;<br>	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">invoke</span><span class="hljs-params">(FilterInvocation fi)</span> <span class="hljs-keyword">throws</span> IOException, ServletException </span>&#123;<br>        <span class="hljs-keyword">if</span> (fi.getRequest() != <span class="hljs-keyword">null</span> &amp;&amp; fi.getRequest().getAttribute(<span class="hljs-string">&quot;__spring_security_filterSecurityInterceptor_filterApplied&quot;</span>) != <span class="hljs-keyword">null</span> &amp;&amp; <span class="hljs-keyword">this</span>.observeOncePerRequest) &#123;<br>            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());<br>        &#125; <span class="hljs-keyword">else</span> &#123;<br>            <span class="hljs-keyword">if</span> (fi.getRequest() != <span class="hljs-keyword">null</span> &amp;&amp; <span class="hljs-keyword">this</span>.observeOncePerRequest) &#123;<br>                fi.getRequest().setAttribute(<span class="hljs-string">&quot;__spring_security_filterSecurityInterceptor_filterApplied&quot;</span>, Boolean.TRUE);<br>            &#125;<br>            InterceptorStatusToken token = <span class="hljs-keyword">super</span>.beforeInvocation(fi);<br>            <span class="hljs-keyword">try</span> &#123;<br>                fi.getChain().doFilter(fi.getRequest(), fi.getResponse());<br>            &#125; <span class="hljs-keyword">finally</span> &#123;<br>                <span class="hljs-keyword">super</span>.finallyInvocation(token);<br>            &#125;<br>            <span class="hljs-keyword">super</span>.afterInvocation(token, (Object)<span class="hljs-keyword">null</span>);<br>        &#125;<br>    &#125;   <br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li><code>super.beforeInvocation(fi)</code> 查看之前的 filter 是否通过</li>
<li><code>fi.getChain().doFilter(fi.getRequest(), fi.getResponse())</code> 真正的调用后台的服务</li>
</ul>
<ol start="2">
<li><code>ExceptionTranslationFilter</code></li>
</ol>
<ul>
<li>异常过滤器，用来处理在认证授权过程中抛出的异常</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExceptionTranslationFilter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">GenericFilterBean</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doFilter</span><span class="hljs-params">(ServletRequest req, ServletResponse res, FilterChain chain)</span> <span class="hljs-keyword">throws</span> IOException, ServletException </span>&#123;<br>        HttpServletRequest request = (HttpServletRequest)req;<br>        HttpServletResponse response = (HttpServletResponse)res;<br>        <span class="hljs-keyword">try</span> &#123;<br>            chain.doFilter(request, response);<br>            <span class="hljs-keyword">this</span>.logger.debug(<span class="hljs-string">&quot;Chain processed normally&quot;</span>);<br>        &#125; <span class="hljs-keyword">catch</span> (IOException var9) &#123;<br>            <span class="hljs-keyword">throw</span> var9;<br>        &#125; <span class="hljs-keyword">catch</span> (Exception var10) &#123;<br>            Throwable[] causeChain = <span class="hljs-keyword">this</span>.throwableAnalyzer.determineCauseChain(var10);<br>            RuntimeException ase = (AuthenticationException)<span class="hljs-keyword">this</span>.throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);<br>            <span class="hljs-keyword">if</span> (ase == <span class="hljs-keyword">null</span>) &#123;<br>                ase = (AccessDeniedException)<span class="hljs-keyword">this</span>.throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);<br>            &#125;<br>            <span class="hljs-keyword">if</span> (ase == <span class="hljs-keyword">null</span>) &#123;<br>                <span class="hljs-keyword">if</span> (var10 <span class="hljs-keyword">instanceof</span> ServletException) &#123;<br>                    <span class="hljs-keyword">throw</span> (ServletException)var10;<br>                &#125;<br>                <span class="hljs-keyword">if</span> (var10 <span class="hljs-keyword">instanceof</span> RuntimeException) &#123;<br>                    <span class="hljs-keyword">throw</span> (RuntimeException)var10;<br>                &#125;<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(var10);<br>            &#125;<br>            <span class="hljs-keyword">if</span> (response.isCommitted()) &#123;<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ServletException(<span class="hljs-string">&quot;Unable to handle the Spring Security Exception because the response is already committed.&quot;</span>, var10);<br>            &#125;<br>            <span class="hljs-keyword">this</span>.handleSpringSecurityException(request, response, chain, (RuntimeException)ase);<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ol start="3">
<li><code>UsernamePasswordAuthenticationFilter</code></li>
</ol>
<ul>
<li>对/login 的 POST 请求做拦截，校验表单中用户名，密码</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UsernamePasswordAuthenticationFilter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AbstractAuthenticationProcessingFilter</span> </span>&#123;<br>        <span class="hljs-function"><span class="hljs-keyword">public</span> Authentication <span class="hljs-title">attemptAuthentication</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response)</span> <span class="hljs-keyword">throws</span> AuthenticationException </span>&#123;<br>        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.postOnly &amp;&amp; !request.getMethod().equals(<span class="hljs-string">&quot;POST&quot;</span>)) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> AuthenticationServiceException(<span class="hljs-string">&quot;Authentication method not supported: &quot;</span> + request.getMethod());<br>        &#125; <span class="hljs-keyword">else</span> &#123;<br>            String username = <span class="hljs-keyword">this</span>.obtainUsername(request);<br>            String password = <span class="hljs-keyword">this</span>.obtainPassword(request);<br>            <span class="hljs-keyword">if</span> (username == <span class="hljs-keyword">null</span>) &#123;<br>                username = <span class="hljs-string">&quot;&quot;</span>;<br>            &#125;<br>            <span class="hljs-keyword">if</span> (password == <span class="hljs-keyword">null</span>) &#123;<br>                password = <span class="hljs-string">&quot;&quot;</span>;<br>            &#125;<br>            username = username.trim();<br>            UsernamePasswordAuthenticationToken authRequest = <span class="hljs-keyword">new</span> UsernamePasswordAuthenticationToken(username, password);<br>            <span class="hljs-keyword">this</span>.setDetails(request, authRequest);<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.getAuthenticationManager().authenticate(authRequest);<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<hr>
<h3 id="4-2-过滤器加载"><a href="#4-2-过滤器加载" class="headerlink" title="4.2 过滤器加载"></a>4.2 过滤器加载</h3><p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210412213111265.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li>过滤器加载通过 <code>DelegatingFilterProxy</code> 来配置加载</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DelegatingFilterProxy</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">GenericFilterBean</span> </span>&#123;<br>	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doFilter</span><span class="hljs-params">(ServletRequest request, ServletResponse response, FilterChain filterChain)</span> <span class="hljs-keyword">throws</span> ServletException, IOException </span>&#123;<br>        Filter delegateToUse = <span class="hljs-keyword">this</span>.delegate;<br>        <span class="hljs-keyword">if</span> (delegateToUse == <span class="hljs-keyword">null</span>) &#123;<br>            <span class="hljs-keyword">synchronized</span>(<span class="hljs-keyword">this</span>.delegateMonitor) &#123;<br>                delegateToUse = <span class="hljs-keyword">this</span>.delegate;<br>                <span class="hljs-keyword">if</span> (delegateToUse == <span class="hljs-keyword">null</span>) &#123;<br>                    WebApplicationContext wac = <span class="hljs-keyword">this</span>.findWebApplicationContext();<br>                    <span class="hljs-keyword">if</span> (wac == <span class="hljs-keyword">null</span>) &#123;<br>                        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException(<span class="hljs-string">&quot;No WebApplicationContext found: no ContextLoaderListener or DispatcherServlet registered?&quot;</span>);<br>                    &#125;<br>                    delegateToUse = <span class="hljs-keyword">this</span>.initDelegate(wac);<br>                &#125;<br>                <span class="hljs-keyword">this</span>.delegate = delegateToUse;<br>            &#125;<br>        &#125;<br>        <span class="hljs-keyword">this</span>.invokeDelegate(delegateToUse, request, response, filterChain);<br>    &#125;   <br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li><code>this.delegate = this.initDelegate(wac)</code>  初始化代理</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">protected</span> Filter <span class="hljs-title">initDelegate</span><span class="hljs-params">(WebApplicationContext wac)</span> <span class="hljs-keyword">throws</span> ServletException </span>&#123;<br>    String targetBeanName = <span class="hljs-keyword">this</span>.getTargetBeanName();<br>    Assert.state(targetBeanName != <span class="hljs-keyword">null</span>, <span class="hljs-string">&quot;No target bean name set&quot;</span>);<br>    Filter delegate = (Filter)wac.getBean(targetBeanName, Filter.class);<br>    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.isTargetFilterLifecycle()) &#123;<br>        delegate.init(<span class="hljs-keyword">this</span>.getFilterConfig());<br>    &#125;<br>    <span class="hljs-keyword">return</span> delegate;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>会内置 <code>FilterChainProxy</code></li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FilterChainProxy</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">GenericFilterBean</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doFilterInternal</span><span class="hljs-params">(ServletRequest request, ServletResponse response, FilterChain chain)</span> </span>&#123;<br>        List&lt;Filter&gt; filters = <span class="hljs-keyword">this</span>.getFilters((HttpServletRequest)fwRequest);<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li><code>private List&lt;Filter&gt; getFilters(HttpServletRequest request)</code> 获取所有过滤器链</li>
</ul>
<hr>
<h3 id="4-3-两个重要接口"><a href="#4-3-两个重要接口" class="headerlink" title="4.3 两个重要接口"></a>4.3 两个重要接口</h3><ol>
<li><code>UserDetailsService</code></li>
</ol>
<ul>
<li>当什么也没有配置的时候，账号和密码是由 Spring Security 定义生成的。如果需要自定义逻辑时，只需要实现 UserDetailsService 接口。</li>
<li><strong>查询数据库用户名和密码过程写在这个接口中</strong></li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserDetailsService</span> </span>&#123;<br>    <span class="hljs-function">UserDetails <span class="hljs-title">loadUserByUsername</span><span class="hljs-params">(String var1)</span> <span class="hljs-keyword">throws</span> UsernameNotFoundException</span>;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>会返回 <code>UserDetails</code> 类，默认为 用户 “主体”</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserDetails</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Serializable</span> </span>&#123;<br>    Collection&lt;? extends GrantedAuthority&gt; getAuthorities(); <span class="hljs-comment">// 获取登录用户所有权限</span><br>    <span class="hljs-function">String <span class="hljs-title">getPassword</span><span class="hljs-params">()</span></span>; 	<span class="hljs-comment">// 获取密码</span><br>    <span class="hljs-function">String <span class="hljs-title">getUsername</span><span class="hljs-params">()</span></span>;	<span class="hljs-comment">// 获取用户名</span><br>    <span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">isAccountNonExpired</span><span class="hljs-params">()</span></span>;<span class="hljs-comment">// 判断账户是否过期</span><br>    <span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">isAccountNonLocked</span><span class="hljs-params">()</span></span>;<span class="hljs-comment">// 判断账户是否被锁定</span><br>    <span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">isCredentialsNonExpired</span><span class="hljs-params">()</span></span>;<span class="hljs-comment">// 凭证&#123;密码&#125;是否过期</span><br>    <span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">isEnabled</span><span class="hljs-params">()</span></span>;	<span class="hljs-comment">// 当前用户是否可用</span><br>&#125;<br></code></pre></div></td></tr></table></figure>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210412215511215.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li>实现类为 <code>User</code>，后面只用实现User这个实体类</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">UserDetails</span>, <span class="hljs-title">CredentialsContainer</span> </span>&#123;<br>    <span class="hljs-comment">//@Param username: 此值是客户端表单传递过来的数据。默认情况下必须叫 username，否则无</span><br>    <span class="hljs-comment">//法接收</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">User</span><span class="hljs-params">(String username, String password, Collection&lt;? extends GrantedAuthority&gt; authorities)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>(username, password, <span class="hljs-keyword">true</span>, <span class="hljs-keyword">true</span>, <span class="hljs-keyword">true</span>, <span class="hljs-keyword">true</span>, authorities);<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li><p>需要做的是：</p>
<ul>
<li><p>创建类继承 <code>UsernamePasswordAuthenticationFilter</code> ，重写三个方法</p>
<ul>
<li><code>attemptAuthentication</code> 尝试认证</li>
<li>父类中的 <code>successfulAuthentication</code> <code>unsuccessfulAuthentication</code> 成功和失败认证</li>
</ul>
</li>
<li><p>创建类实现 <code>UserDetailsService</code> ，编写查询数据过程，返回 User 对象，该User是安全框架提供的。</p>
</li>
</ul>
</li>
</ul>
<hr>
<ol start="2">
<li><code>PasswordEncoder</code></li>
</ol>
<ul>
<li><strong>数据加密接口，用于返回User对象里面密码加密</strong></li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">PasswordEncoder</span> </span>&#123;<br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 表示把参数按照特定的解析规则进行解析</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-function">String <span class="hljs-title">encode</span><span class="hljs-params">(CharSequence var1)</span></span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 验证从存储中获取的编码密码与编码后提交的原始密码是否匹配</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> var1 需要被解析的密码</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> var2 存储的密码</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 密码匹配 true, 不匹配 false</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">matches</span><span class="hljs-params">(CharSequence var1, String var2)</span></span>;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 升级密码</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> encodedPassword 编译后的密码</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 解析的密码能够再次进行解析且达到更安全的结果 true, 否则返回</span><br><span class="hljs-comment">     *         false。默认返回 false</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-function"><span class="hljs-keyword">default</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">upgradeEncoding</span><span class="hljs-params">(String encodedPassword)</span> </span>&#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210412220820356.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li><code>BCryptPasswordEncoder</code> 是 Spring Security 官方推荐的密码解析器，平时多使用这个解析器，对 bcrypt 强散列方法的具体实现。是基于 Hash 算法实现的单向加密。可以通过 strength 控制加密强度，默认 10。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">test01</span><span class="hljs-params">()</span> </span>&#123;<br>    <span class="hljs-comment">// 创建密码解析器</span><br>    BCryptPasswordEncoder bCryptPasswordEncoder = <span class="hljs-keyword">new</span> BCryptPasswordEncoder();<br>    <span class="hljs-comment">// 对密码进行加密</span><br>    String testStr = bCryptPasswordEncoder.encode(<span class="hljs-string">&quot;test&quot;</span>);<br>    <span class="hljs-comment">// 打印加密之后的数据</span><br>    System.out.println(<span class="hljs-string">&quot; 加密之后数据：\t&quot;</span> + testStr);<br>    <span class="hljs-comment">// 判断原字符加密后和加密之前是否匹配</span><br>    <span class="hljs-keyword">boolean</span> result = bCryptPasswordEncoder.matches(<span class="hljs-string">&quot;test&quot;</span>, testStr);<br>    <span class="hljs-comment">// 打印比较结果</span><br>    System.out.println(<span class="hljs-string">&quot; 比较结果：\t&quot;</span> + result);<br>&#125;<br></code></pre></div></td></tr></table></figure>


<h2 id="5-SpringSecurity-Web-权限方案"><a href="#5-SpringSecurity-Web-权限方案" class="headerlink" title="5 SpringSecurity Web 权限方案"></a>5 SpringSecurity Web 权限方案</h2><blockquote>
<p>spring-boot-starter-parent 2.2.1.RELEASE;  spring-security-web  5.2.1.RELEASE</p>
</blockquote>
<h3 id="5-1-设置登录系统的账号、密码"><a href="#5-1-设置登录系统的账号、密码" class="headerlink" title="5.1 设置登录系统的账号、密码"></a>5.1 设置登录系统的账号、密码</h3><h4 id="方式一：application-properties"><a href="#方式一：application-properties" class="headerlink" title="方式一：application.properties"></a>方式一：application.properties</h4><figure class="highlight properties"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs properties"><span class="hljs-meta">spring.security.user.name</span>=<span class="hljs-string">hypocrite30</span><br><span class="hljs-meta">spring.security.user.password</span>=<span class="hljs-string">hypocrite30</span><br></code></pre></div></td></tr></table></figure>
<h4 id="方式二：编写类实现接口"><a href="#方式二：编写类实现接口" class="headerlink" title="方式二：编写类实现接口"></a>方式二：编写类实现接口</h4><ul>
<li><code>config</code> 包下创建 Security 的<strong>配置类</strong></li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Configuration</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SecurityConfig</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">WebSecurityConfigurerAdapter</span> </span>&#123;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configure</span><span class="hljs-params">(AuthenticationManagerBuilder auth)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        BCryptPasswordEncoder passwordEncoder = <span class="hljs-keyword">new</span> BCryptPasswordEncoder();<br>        String password = passwordEncoder.encode(<span class="hljs-string">&quot;123&quot;</span>); <span class="hljs-comment">// 对密码进行编译</span><br>        auth.inMemoryAuthentication().withUser(<span class="hljs-string">&quot;hypocrite30&quot;</span>).password(password).roles(<span class="hljs-string">&quot;admin&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-comment">// 注入密码编码器</span><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-function">PasswordEncoder <span class="hljs-title">password</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BCryptPasswordEncoder();<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<h4 id="方式三：自定义实现类"><a href="#方式三：自定义实现类" class="headerlink" title="方式三：自定义实现类"></a>方式三：自定义实现类</h4><ul>
<li>创建配置类，设置使用哪个<code>userDetailsService</code>实现类</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Configuration</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SecurityConfigTest</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">WebSecurityConfigurerAdapter</span> </span>&#123;<br>	<span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> UserDetailsService userDetailsService;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configure</span><span class="hljs-params">(AuthenticationManagerBuilder auth)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        auth.userDetailsService(userDetailsService).passwordEncoder(password());<br>    &#125;<br>    <span class="hljs-comment">// 注入密码编码器</span><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-function">PasswordEncoder <span class="hljs-title">password</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BCryptPasswordEncoder();<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li><code>userDetailsService</code> 选择使用哪个 Service进行认证</li>
<li>编写实现类，返回User对象，User对象有用户名密码和权限</li>
</ul>
<figure class="highlight haxe"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs haxe">@Service(<span class="hljs-string">&quot;userDetailsService&quot;</span>) <span class="hljs-comment">// 与注入的名称一一对应</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyUserDetailsService</span> <span class="hljs-keyword"><span class="hljs-keyword">implements</span> <span class="hljs-type">UserDetailsService</span></span> </span>&#123;<br>	@Override<br>    <span class="hljs-keyword">public</span> UserDetails loadUserByUsername(<span class="hljs-keyword">String</span> s) throws UsernameNotFoundException &#123;<br>        List&lt;GrantedAuthority&gt; auths =<br>                AuthorityUtils.commaSeparatedStringToAuthorityList(<span class="hljs-string">&quot;role&quot;</span>);<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-type">User</span>(<span class="hljs-string">&quot;hypocrite30&quot;</span>,<br>                <span class="hljs-keyword">new</span> <span class="hljs-type">BCryptPasswordEncoder</span>().encode(<span class="hljs-string">&quot;password&quot;</span>), auths);<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<blockquote>
<p>一般都是用<strong>第三种</strong>方法，自定义实现类。但是涉及到管理员模式，可以使用第一和第二种方式设置admin。</p>
</blockquote>
<h3 id="5-2-整合数据库完成用户认证"><a href="#5-2-整合数据库完成用户认证" class="headerlink" title="5.2 整合数据库完成用户认证"></a>5.2 整合数据库完成用户认证</h3><ul>
<li>整合Mybatis-plus</li>
</ul>
<figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!--mybatis-plus--&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.baomidou<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mybatis-plus-boot-starter<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.0.5<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><span class="hljs-comment">&lt;!--mysql--&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>mysql<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mysql-connector-java<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.projectlombok<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>lombok<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></div></td></tr></table></figure>
<ul>
<li>创表 users</li>
</ul>
<figure class="highlight sql"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs sql"><span class="hljs-keyword">SET</span> NAMES utf8mb4;<br><span class="hljs-keyword">SET</span> FOREIGN_KEY_CHECKS <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;<br><span class="hljs-comment">-- ----------------------------</span><br><span class="hljs-comment">-- Table structure for users</span><br><span class="hljs-comment">-- ----------------------------</span><br><span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> IF <span class="hljs-keyword">EXISTS</span> `users`;<br><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> `users`  (<br>  `id` <span class="hljs-type">int</span>(<span class="hljs-number">0</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  `username` <span class="hljs-type">varchar</span>(<span class="hljs-number">10</span>) <span class="hljs-type">CHARACTER</span> <span class="hljs-keyword">SET</span> utf8 <span class="hljs-keyword">COLLATE</span> utf8_general_ci <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span>,<br>  `password` <span class="hljs-type">varchar</span>(<span class="hljs-number">10</span>) <span class="hljs-type">CHARACTER</span> <span class="hljs-keyword">SET</span> utf8 <span class="hljs-keyword">COLLATE</span> utf8_general_ci <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span>,<br>  <span class="hljs-keyword">PRIMARY</span> KEY (`id`) <span class="hljs-keyword">USING</span> BTREE<br>) ENGINE <span class="hljs-operator">=</span> InnoDB <span class="hljs-type">CHARACTER</span> <span class="hljs-keyword">SET</span> <span class="hljs-operator">=</span> utf8 <span class="hljs-keyword">COLLATE</span> <span class="hljs-operator">=</span> utf8_general_ci ROW_FORMAT <span class="hljs-operator">=</span> <span class="hljs-keyword">Dynamic</span>;<br><br><span class="hljs-comment">-- ----------------------------</span><br><span class="hljs-comment">-- Records of users</span><br><span class="hljs-comment">-- ----------------------------</span><br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> `users` <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-string">&#x27;lucy&#x27;</span>, <span class="hljs-string">&#x27;123&#x27;</span>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> `users` <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">2</span>, <span class="hljs-string">&#x27;mary&#x27;</span>, <span class="hljs-string">&#x27;456&#x27;</span>);<br><span class="hljs-keyword">SET</span> FOREIGN_KEY_CHECKS <span class="hljs-operator">=</span> <span class="hljs-number">1</span>;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>创建实体类，<code>entity</code>包下</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Data</span><br><span class="hljs-meta">@AllArgsConstructor</span><br><span class="hljs-meta">@NoArgsConstructor</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Users</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> Integer id;<br>    <span class="hljs-keyword">private</span> String username;<br>    <span class="hljs-keyword">private</span> String password;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>整合Mybatis-plus，创建mapper，放在mapper包下</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Repository</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UsersMapper</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">BaseMapper</span>&lt;<span class="hljs-title">Users</span>&gt; </span>&#123;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>有Mapper，就需要在启动类上添加@MapperScan扫描</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@MapperScan(&quot;com.xxx.security.mapper&quot;)</span> <span class="hljs-comment">// mapper对应的包路径</span><br></code></pre></div></td></tr></table></figure>
<ul>
<li>配置文件加上数据库连接信息</li>
</ul>
<figure class="highlight properties"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs properties"><span class="hljs-meta">spring.datasource.driver-class-name</span>=<span class="hljs-string">com.mysql.cj.jdbc.Driver</span><br><span class="hljs-meta">spring.datasource.url</span>=<span class="hljs-string">jdbc:mysql://localhost:3306/springsecurity?serverTimezone=Asia/Shanghai&amp;useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=true</span><br><span class="hljs-meta">spring.datasource.username</span>=<span class="hljs-string">root</span><br><span class="hljs-meta">spring.datasource.password</span>=<span class="hljs-string">root</span><br></code></pre></div></td></tr></table></figure>
<ul>
<li>在自定义实现类中调用mapper查询数据库用户名认证</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Service(&quot;userDetailsService&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyUserDetailsService</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">UserDetailsService</span> </span>&#123;<br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> UsersMapper usersMapper;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> UserDetails <span class="hljs-title">loadUserByUsername</span><span class="hljs-params">(String username)</span> <span class="hljs-keyword">throws</span> UsernameNotFoundException </span>&#123;<br>        <span class="hljs-comment">//调用usersMapper方法，根据用户名查询数据库</span><br>        QueryWrapper&lt;Users&gt; wrapper = <span class="hljs-keyword">new</span> QueryWrapper();<br>        <span class="hljs-comment">// where username=?</span><br>        wrapper.eq(<span class="hljs-string">&quot;username&quot;</span>, username);<br>        Users users = usersMapper.selectOne(wrapper);<br>        <span class="hljs-comment">//判断</span><br>        <span class="hljs-keyword">if</span> (users == <span class="hljs-keyword">null</span>) &#123;<span class="hljs-comment">//数据库没有用户名，认证失败</span><br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UsernameNotFoundException(<span class="hljs-string">&quot;用户名不存在！&quot;</span>);<br>        &#125;<br>        List&lt;GrantedAuthority&gt; auths =<br>                AuthorityUtils.commaSeparatedStringToAuthorityList(<span class="hljs-string">&quot;role&quot;</span>);<br>        <span class="hljs-comment">//从查询数据库返回users对象，得到用户名和密码，返回</span><br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> User(users.getUsername(),<br>                <span class="hljs-keyword">new</span> BCryptPasswordEncoder().encode(users.getPassword()), auths);<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<h3 id="5-3-自定义登录界面-amp-控制是否认证"><a href="#5-3-自定义登录界面-amp-控制是否认证" class="headerlink" title="5.3 自定义登录界面 &amp; 控制是否认证"></a>5.3 自定义登录界面 &amp; 控制是否认证</h3><ul>
<li>在Security配置类进行配置，注意重写的是 形参<code>HttpSecurity http</code> 的 configure()</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-comment">// 配置认证</span><br><span class="hljs-meta">@Override</span><br><span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configure</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>    http.formLogin() <span class="hljs-comment">// 自定义自己编写的登录页面</span><br>            .loginPage(<span class="hljs-string">&quot;/login.html&quot;</span>) <span class="hljs-comment">//  配置哪个 url 为登录页面</span><br>            .loginProcessingUrl(<span class="hljs-string">&quot;/user/login&quot;</span>) <span class="hljs-comment">// 登录访问路径 url</span><br>            .successForwardUrl(<span class="hljs-string">&quot;/success&quot;</span>) <span class="hljs-comment">//  登录成功之后，跳转路径 url</span><br>            .failureForwardUrl(<span class="hljs-string">&quot;/fail&quot;</span>);<span class="hljs-comment">//  登录失败之后跳转到哪个 url</span><br>    http.authorizeRequests()<br>            .antMatchers(<span class="hljs-string">&quot;/test/hello&quot;</span>, <span class="hljs-string">&quot;/login&quot;</span>) <span class="hljs-comment">// 表示配置请求路径</span><br>            .permitAll() <span class="hljs-comment">// 指定 URL 无需认证。</span><br>            .anyRequest() <span class="hljs-comment">// 其他请求</span><br>            .authenticated(); <span class="hljs-comment">// 需要认证</span><br>    http.csrf().disable(); <span class="hljs-comment">// 关闭 csrf</span><br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>controller</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@PostMapping(&quot;/success&quot;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">success</span><span class="hljs-params">()</span> </span>&#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;success&quot;</span>;<br>&#125;<br><span class="hljs-meta">@PostMapping(&quot;/fail&quot;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">fail</span><span class="hljs-params">()</span> </span>&#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;fail&quot;</span>;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>前端表单</li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">&quot;/login&quot;</span><span class="hljs-attr">method</span>=<span class="hljs-string">&quot;post&quot;</span>&gt;</span><br>用户名:<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;text&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;username&quot;</span>/&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>/&gt;</span> // username，password名称不能错<br>密码：<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;password&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;password&quot;</span>/&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>/&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;submit&quot;</span><span class="hljs-attr">value</span>=<span class="hljs-string">&quot; 提交&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span><br></code></pre></div></td></tr></table></figure>
<h3 id="5-4-基于角色或权限进行访问控制"><a href="#5-4-基于角色或权限进行访问控制" class="headerlink" title="5.4 基于角色或权限进行访问控制"></a>5.4 基于角色或权限进行访问控制</h3><h4 id="「hasAuthority」"><a href="#「hasAuthority」" class="headerlink" title="「hasAuthority」"></a>「hasAuthority」</h4><ul>
<li><p>如果当前的主体具有指定权限，返回true，否则返回false。</p>
</li>
<li><p>配置类加上路径和能访问的权限</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">.antMatchers(<span class="hljs-string">&quot;/test/index&quot;</span>).hasAuthority(<span class="hljs-string">&quot;admins&quot;</span>)<br></code></pre></div></td></tr></table></figure>
<ul>
<li>自定义Service上为返回的User对象加权限</li>
</ul>
<figure class="highlight reasonml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs reasonml">List&lt;GrantedAuthority&gt; auths =<br>        <span class="hljs-module-access"><span class="hljs-module"><span class="hljs-identifier">AuthorityUtils</span>.</span></span>comma<span class="hljs-constructor">SeparatedStringToAuthorityList(<span class="hljs-string">&quot;admins&quot;</span>)</span>;<br></code></pre></div></td></tr></table></figure>
<h4 id="「hasAnyAuthority」"><a href="#「hasAnyAuthority」" class="headerlink" title="「hasAnyAuthority」"></a>「hasAnyAuthority」</h4><ul>
<li>区别于上面的单个角色，此方法添加多个权限</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">.antMatchers(<span class="hljs-string">&quot;/test/index&quot;</span>).hasAnyAuthority(<span class="hljs-string">&quot;admins, manager&quot;</span>)<br></code></pre></div></td></tr></table></figure>
<h4 id="「hasRole」"><a href="#「hasRole」" class="headerlink" title="「hasRole」"></a>「hasRole」</h4><ul>
<li>如果用户具备给定角色就允许访问，否则403</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">.antMatchers(<span class="hljs-string">&quot;/test/index&quot;</span>).hasRole(<span class="hljs-string">&quot;sale&quot;</span>)<br></code></pre></div></td></tr></table></figure>
<ul>
<li>注：hasRole() 参数<strong>不能</strong>加 “<code>ROLE_</code>“，会抛出异常</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">hasRole</span><span class="hljs-params">(String role)</span> </span>&#123;<br>    Assert.notNull(role, <span class="hljs-string">&quot;role cannot be null&quot;</span>);<br>    <span class="hljs-keyword">if</span> (role.startsWith(<span class="hljs-string">&quot;ROLE_&quot;</span>)) &#123;<br>        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">&quot;role should not start with &#x27;ROLE_&#x27; since it is automatically inserted. Got &#x27;&quot;</span> + role + <span class="hljs-string">&quot;&#x27;&quot;</span>);<br>    &#125; <span class="hljs-keyword">else</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;hasRole(&#x27;ROLE_&quot;</span> + role + <span class="hljs-string">&quot;&#x27;)&quot;</span>;<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">.antMatchers(<span class="hljs-string">&quot;/test/index&quot;</span>).access(<span class="hljs-string">&quot;hasRole(&#x27;sale&#x27;)&quot;</span>) <span class="hljs-comment">// 这种写法同上，可加ROLE_，可不加</span><br></code></pre></div></td></tr></table></figure>
<ul>
<li>给用户添加角色，需要加上前缀</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">List&lt;GrantedAuthority&gt; auths =<br>        AuthorityUtils.commaSeparatedStringToAuthorityList(<span class="hljs-string">&quot;admin,ROLE_sale&quot;</span>);<br></code></pre></div></td></tr></table></figure>
<h4 id="「hasAnyRole」"><a href="#「hasAnyRole」" class="headerlink" title="「hasAnyRole」"></a>「hasAnyRole」</h4><ul>
<li>同上，可添加多个，同样注意加前缀。</li>
</ul>
<h3 id="5-5-自定义403界面"><a href="#5-5-自定义403界面" class="headerlink" title="5.5 自定义403界面"></a>5.5 自定义403界面</h3><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-comment">//配置没有权限访问跳转自定义页面</span><br>http.exceptionHandling().accessDeniedPage(<span class="hljs-string">&quot;/unauth.html&quot;</span>); <span class="hljs-comment">// 跳转到自定义403界面</span><br></code></pre></div></td></tr></table></figure>
<ul>
<li>跳转的路径也可以是controller进行跳转</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">http.exceptionHandling().accessDeniedPage(<span class="hljs-string">&quot;/unauth&quot;</span>);<br><br><span class="hljs-meta">@GetMapping(&quot;/unauth&quot;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">accessDenyPage</span><span class="hljs-params">()</span></span>&#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;unauth&quot;</span>;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<h3 id="5-6-注解"><a href="#5-6-注解" class="headerlink" title="5.6 注解"></a>5.6 注解</h3><h4 id="「-Secured」"><a href="#「-Secured」" class="headerlink" title="「@Secured」"></a>「@Secured」</h4><ul>
<li><p>判断是否具有<strong>角色</strong>，另外需要注意的是这里匹配的字符串需要添加前缀 <code>ROLE_</code>。</p>
</li>
<li><p>开启注解功能(下面的注解都要打开注解功能)</p>
</li>
</ul>
<p><code>@EnableGlobalMethodSecurity(securedEnabled=true)</code> 可以加在<strong>启动类</strong>或<strong>配置类</strong>上</p>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@SpringBootApplication</span><br><span class="hljs-meta">@EnableGlobalMethodSecurity(securedEnabled=true)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DemosecurityApplication</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;<br>        SpringApplication.run(DemosecurityApplication.class, args);<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>在控制器方法上添加注解</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@GetMapping(&quot;update&quot;)</span><br><span class="hljs-meta">@Secured(&#123;&quot;ROLE_sale&quot;,&quot;ROLE_manager&quot;&#125;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">update</span><span class="hljs-params">()</span> </span>&#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;hello update&quot;</span>;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<h4 id="「-PreAuthorize」"><a href="#「-PreAuthorize」" class="headerlink" title="「@PreAuthorize」"></a>「@PreAuthorize」</h4><ul>
<li>注解适合<strong>进入方法前</strong>的权限验证，判断的是有无<strong>权限</strong></li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@RequestMapping(&quot;/preAuthorize&quot;)</span><br><span class="hljs-comment">//@PreAuthorize(&quot;hasRole(&#x27;admins&#x27;)&quot;)</span><br><span class="hljs-meta">@PreAuthorize(&quot;hasAnyAuthority(&#x27;admins&#x27;)&quot;)</span> <span class="hljs-comment">//上面的四种方法都可以</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">preAuthorize</span><span class="hljs-params">()</span></span>&#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;preAuthorize&quot;</span>;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<h4 id="「-PostAuthorize」"><a href="#「-PostAuthorize」" class="headerlink" title="「@PostAuthorize」"></a>「@PostAuthorize」</h4><ul>
<li>注解使用并不多，在方法执行后再进行权限验证，适合验证带有返回值的权限</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@RequestMapping(&quot;/testPostAuthorize&quot;)</span><br><span class="hljs-meta">@PostAuthorize(&quot;hasAnyAuthority(&#x27;admins&#x27;)&quot;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">preAuthorize</span><span class="hljs-params">()</span></span>&#123;<br>    System.out.println(<span class="hljs-string">&quot;test--PostAuthorize&quot;</span>);<br>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;PostAuthorize&quot;</span>;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>无权限登录完后虽然会虽然会进入403，但是方法里的sout依然会执行</li>
</ul>
<h4 id="「-PreFilter」"><a href="#「-PreFilter」" class="headerlink" title="「@PreFilter」"></a>「@PreFilter」</h4><ul>
<li>不常用，进入控制器之前对数据进行过滤，一般就是对特定的数据拦截</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@RequestMapping(&quot;getTestPreFilter&quot;)</span><br><span class="hljs-meta">@PreAuthorize(&quot;hasRole(&#x27;admins&#x27;)&quot;)</span><br><span class="hljs-meta">@PreFilter(&quot;filterObject.id%2 == 0&quot;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;Users&gt; <span class="hljs-title">getTestPreFilter</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> List&lt;Users&gt; list)</span> </span>&#123;<br>    list.forEach(t -&gt; &#123;<br>        System.out.println(t.getId() + <span class="hljs-string">&quot;\t&quot;</span> + t.getUsername());<br>    &#125;);<br>    <span class="hljs-keyword">return</span> list;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<h4 id="「-PostFilter」"><a href="#「-PostFilter」" class="headerlink" title="「@PostFilter」"></a>「@PostFilter」</h4><ul>
<li>不常用，权限验证<strong>之后</strong>对数据进行过滤，留下用户名是 admin1 的数据</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@GetMapping(&quot;getAll&quot;)</span><br><span class="hljs-meta">@PostAuthorize(&quot;hasAnyAuthority(&#x27;admin&#x27;)&quot;)</span><br><span class="hljs-meta">@PostFilter(&quot;filterObject.username == &#x27;admin1&#x27;&quot;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;Users&gt; <span class="hljs-title">getAllUser</span><span class="hljs-params">()</span> </span>&#123;<br>    ArrayList&lt;Users&gt; list = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();<br>    list.add(<span class="hljs-keyword">new</span> Users(<span class="hljs-number">11</span>, <span class="hljs-string">&quot;admin1&quot;</span>, <span class="hljs-string">&quot;6666&quot;</span>));<br>    list.add(<span class="hljs-keyword">new</span> Users(<span class="hljs-number">21</span>, <span class="hljs-string">&quot;admin2&quot;</span>, <span class="hljs-string">&quot;888&quot;</span>));<br>    System.out.println(list);<br>    <span class="hljs-keyword">return</span> list;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<h3 id="5-7-注销"><a href="#5-7-注销" class="headerlink" title="5.7 注销"></a>5.7 注销</h3><ul>
<li>配置类的<code>configure</code> 方法</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-comment">//退出</span><br>http.logout().logoutUrl(<span class="hljs-string">&quot;/logout&quot;</span>).<br>        logoutSuccessUrl(<span class="hljs-string">&quot;/test/hello&quot;</span>).permitAll();<br></code></pre></div></td></tr></table></figure>
<ul>
<li>测试可以先成功登录，再访问资源，退出后再访问相同资源需要登录。</li>
</ul>
<h3 id="5-8-RememberMe功能"><a href="#5-8-RememberMe功能" class="headerlink" title="5.8 RememberMe功能"></a>5.8 RememberMe功能</h3><p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210414195940770.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li>数据库创表</li>
</ul>
<figure class="highlight sql"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> `persistent_logins`  (<br>  `username` <span class="hljs-type">varchar</span>(<span class="hljs-number">64</span>) <span class="hljs-type">CHARACTER</span> <span class="hljs-keyword">SET</span> utf8 <span class="hljs-keyword">COLLATE</span> utf8_general_ci <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  `series` <span class="hljs-type">varchar</span>(<span class="hljs-number">64</span>) <span class="hljs-type">CHARACTER</span> <span class="hljs-keyword">SET</span> utf8 <span class="hljs-keyword">COLLATE</span> utf8_general_ci <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  `token` <span class="hljs-type">varchar</span>(<span class="hljs-number">64</span>) <span class="hljs-type">CHARACTER</span> <span class="hljs-keyword">SET</span> utf8 <span class="hljs-keyword">COLLATE</span> utf8_general_ci <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  `last_used` <span class="hljs-type">timestamp</span>(<span class="hljs-number">0</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span>,<br>  <span class="hljs-keyword">PRIMARY</span> KEY (`series`) <span class="hljs-keyword">USING</span> BTREE<br>) ENGINE <span class="hljs-operator">=</span> InnoDB <span class="hljs-type">CHARACTER</span> <span class="hljs-keyword">SET</span> <span class="hljs-operator">=</span> utf8 <span class="hljs-keyword">COLLATE</span> <span class="hljs-operator">=</span> utf8_general_ci ROW_FORMAT <span class="hljs-operator">=</span> <span class="hljs-keyword">Dynamic</span>;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>配置类注入数据源，配置操作数据库对象</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-comment">//注入数据源</span><br><span class="hljs-meta">@Autowired</span><br><span class="hljs-keyword">private</span> DataSource dataSource;<br><span class="hljs-comment">//配置对象</span><br><span class="hljs-meta">@Bean</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> PersistentTokenRepository <span class="hljs-title">persistentTokenRepository</span><span class="hljs-params">()</span> </span>&#123;<br>    JdbcTokenRepositoryImpl jdbcTokenRepository = <span class="hljs-keyword">new</span> JdbcTokenRepositoryImpl();<br>    jdbcTokenRepository.setDataSource(dataSource);<br>    <span class="hljs-comment">//jdbcTokenRepository.setCreateTableOnStartup(true); 自动把表创建</span><br>    <span class="hljs-keyword">return</span> jdbcTokenRepository;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>配置类配置自动登录</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">.and()<br>.rememberMe().tokenRepository(persistentTokenRepository()) <span class="hljs-comment">// 设置使用的repository</span><br>.tokenValiditySeconds(<span class="hljs-number">60</span>)   <span class="hljs-comment">//设置有效时长，单位秒</span><br>.userDetailsService(userDetailsService);<br></code></pre></div></td></tr></table></figure>
<ul>
<li>前端的自动登录的checkbox的name必须是 <code>remember-me</code></li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;checkbox&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;remember-me&quot;</span>/&gt;</span> 自动登录<br></code></pre></div></td></tr></table></figure>


<h4 id="「RememberMe原理」"><a href="#「RememberMe原理」" class="headerlink" title="「RememberMe原理」"></a>「RememberMe原理」</h4><p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210413220252425.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li><p>第一次认证的流程走上面的路线（1-4），第二次（11-14）</p>
</li>
<li><p>看到 <code>UsernamePasswordAuthenticationFilter</code> 的父类 <code>AbstractAuthenticationProcessingFilter</code>的 <code>doFilter</code> 方法在成功认证后，调用 <code>successfulAuthentication</code> 方法</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">successfulAuthentication</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult)</span> <span class="hljs-keyword">throws</span> IOException, ServletException </span>&#123;<br>    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.logger.isDebugEnabled()) &#123;<br>        <span class="hljs-keyword">this</span>.logger.debug(<span class="hljs-string">&quot;Authentication success. Updating SecurityContextHolder to contain: &quot;</span> + authResult);<br>    &#125;<br><br>    SecurityContextHolder.getContext().setAuthentication(authResult);<br>    <span class="hljs-keyword">this</span>.rememberMeServices.loginSuccess(request, response, authResult);<br>    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.eventPublisher != <span class="hljs-keyword">null</span>) &#123;<br>        <span class="hljs-keyword">this</span>.eventPublisher.publishEvent(<span class="hljs-keyword">new</span> InteractiveAuthenticationSuccessEvent(authResult, <span class="hljs-keyword">this</span>.getClass()));<br>    &#125;<br><br>    <span class="hljs-keyword">this</span>.successHandler.onAuthenticationSuccess(request, response, authResult);<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li><code>this.rememberMeServices.loginSuccess(request, response, authResult);</code>继续跟进</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">RememberMeServices</span> </span>&#123;<br>    <span class="hljs-function">Authentication <span class="hljs-title">autoLogin</span><span class="hljs-params">(HttpServletRequest var1, HttpServletResponse var2)</span></span>;<br><br>    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">loginFail</span><span class="hljs-params">(HttpServletRequest var1, HttpServletResponse var2)</span></span>;<br><br>    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">loginSuccess</span><span class="hljs-params">(HttpServletRequest var1, HttpServletResponse var2, Authentication var3)</span></span>;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>在其实现类 <code>AbstractRememberMeServices</code>中</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-title">loginSuccess</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication)</span> </span>&#123;<br>    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.rememberMeRequested(request, <span class="hljs-keyword">this</span>.parameter)) &#123;<br>        <span class="hljs-keyword">this</span>.logger.debug(<span class="hljs-string">&quot;Remember-me login not requested.&quot;</span>);<br>    &#125; <span class="hljs-keyword">else</span> &#123;<br>        <span class="hljs-keyword">this</span>.onLoginSuccess(request, response, successfulAuthentication);<br>    &#125;<br>&#125;<br><br><span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onLoginSuccess</span><span class="hljs-params">(HttpServletRequest var1, HttpServletResponse var2, Authentication var3)</span></span>;<br></code></pre></div></td></tr></table></figure>
<ul>
<li><code>onLoginSuccess</code> 由实现类 <code>PersistentTokenBasedRememberMeServices</code> 实现</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onLoginSuccess</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication)</span> </span>&#123;<br>    String username = successfulAuthentication.getName();<br>    <span class="hljs-keyword">this</span>.logger.debug(<span class="hljs-string">&quot;Creating new persistent login for user &quot;</span> + username);<br>    PersistentRememberMeToken persistentToken = <span class="hljs-keyword">new</span> PersistentRememberMeToken(username, <span class="hljs-keyword">this</span>.generateSeriesData(), <span class="hljs-keyword">this</span>.generateTokenData(), <span class="hljs-keyword">new</span> Date());<br>    <span class="hljs-keyword">try</span> &#123;<br>        <span class="hljs-keyword">this</span>.tokenRepository.createNewToken(persistentToken);<br>        <span class="hljs-keyword">this</span>.addCookie(persistentToken, request, response);<br>    &#125; <span class="hljs-keyword">catch</span> (Exception var7) &#123;<br>        <span class="hljs-keyword">this</span>.logger.error(<span class="hljs-string">&quot;Failed to save persistent token &quot;</span>, var7);<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li><code>this.tokenRepository.createNewToken(persistentToken)</code> 通过<code>tokenRepository</code>，创建新Token，然后通过cookie传回给浏览器，另一边写入数据库做备份。</li>
<li>在 <code>public class JdbcTokenRepositoryImpl</code> 中会对数据库进行操作，让Token存入数据库中。</li>
</ul>
<hr>
<ul>
<li>「记住我」之后，下次的请求过程是</li>
<li>先被 <code>RememberMeAuthenticationFilter</code> 过滤器过滤，其中的 <code>doFilter </code> 方法会完成自动登录</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doFilter</span><span class="hljs-params">(ServletRequest req, ServletResponse res, FilterChain chain)</span> <span class="hljs-keyword">throws</span> IOException, ServletException </span>&#123;<br>    HttpServletRequest request = (HttpServletRequest)req;<br>    HttpServletResponse response = (HttpServletResponse)res;<br>    <span class="hljs-keyword">if</span> (SecurityContextHolder.getContext().getAuthentication() == <span class="hljs-keyword">null</span>) &#123;<br>        Authentication rememberMeAuth = <span class="hljs-keyword">this</span>.rememberMeServices.autoLogin(request, response);<br></code></pre></div></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">RememberMeServices</span> </span>&#123;<br>    <span class="hljs-function">Authentication <span class="hljs-title">autoLogin</span><span class="hljs-params">(HttpServletRequest var1, HttpServletResponse var2)</span></span>;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>实现类 <code>AbstractRememberMeServices</code> </li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> Authentication <span class="hljs-title">autoLogin</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response)</span> </span>&#123;<br>    String rememberMeCookie = <span class="hljs-keyword">this</span>.extractRememberMeCookie(request);<br>    <span class="hljs-keyword">if</span> (rememberMeCookie == <span class="hljs-keyword">null</span>) &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;<br>    &#125; <span class="hljs-keyword">else</span> &#123;<br>        <span class="hljs-keyword">this</span>.logger.debug(<span class="hljs-string">&quot;Remember-me cookie detected&quot;</span>);<br>        <span class="hljs-keyword">if</span> (rememberMeCookie.length() == <span class="hljs-number">0</span>) &#123;<br>            <span class="hljs-keyword">this</span>.logger.debug(<span class="hljs-string">&quot;Cookie was empty&quot;</span>);<br>            <span class="hljs-keyword">this</span>.cancelCookie(request, response);<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;<br>        &#125; <span class="hljs-keyword">else</span> &#123;<br>            UserDetails user = <span class="hljs-keyword">null</span>;<br>            <span class="hljs-keyword">try</span> &#123;<br>                String[] cookieTokens = <span class="hljs-keyword">this</span>.decodeCookie(rememberMeCookie);<br>                user = <span class="hljs-keyword">this</span>.processAutoLoginCookie(cookieTokens, request, response);<br>                <span class="hljs-keyword">this</span>.userDetailsChecker.check(user);<br>                <span class="hljs-keyword">this</span>.logger.debug(<span class="hljs-string">&quot;Remember-me cookie accepted&quot;</span>);<br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.createSuccessfulAuthentication(request, user);<br></code></pre></div></td></tr></table></figure>
<ul>
<li>前面判空。然后 try 里头对cookie解码，再调用 <code>processAutoLoginCookie</code> </li>
<li>在实现类中 <code>PersistentTokenBasedRememberMeServices</code> </li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">protected</span> UserDetails <span class="hljs-title">processAutoLoginCookie</span><span class="hljs-params">(String[] cookieTokens, HttpServletRequest request, HttpServletResponse response)</span> </span>&#123;<br>    ....<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.getUserDetailsService().loadUserByUsername(token.getUsername());<br></code></pre></div></td></tr></table></figure>
<ul>
<li>调用 <code>loadUserByUsername</code> ，即接口 <code>UserDetailsService</code> 里的实现类调用此方法进行数据库的查询，返回之前在数据库中存的cookie，然后进行 <code>check</code> 比对，成功则直接return，<code>createSuccessfulAuthentication</code>成功认证。</li>
</ul>
<h3 id="5-9-CSRF"><a href="#5-9-CSRF" class="headerlink" title="5.9 CSRF"></a>5.9 CSRF</h3><ul>
<li><p>跨站请求伪造（Cross-site request forgery），可以理解为网站读取已经存在的cookie用来做恶意认证。</p>
</li>
<li><p>从 Spring Security 4.0 开始，默认情况下会启用 CSRF 保护，以防止 CSRF 攻击应用程序，Spring Security CSRF 会针对 <code>PATCH</code>，<code>POST</code>，<code>PUT</code> 和 DELETE 方法进行防护。主要是针对数据库操作的请求防护。</p>
</li>
</ul>
<ul>
<li>导入thymeleaf-security</li>
</ul>
<figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">&lt;!--对Thymeleaf添加Spring Security标签支持--&gt;<br>&lt;dependency&gt;<br>    &lt;groupId&gt;org.thymeleaf.extras&lt;/groupId&gt;<br>    &lt;artifactId&gt;thymeleaf-extras-springsecurity5&lt;/artifactId&gt;<br>&lt;/dependency&gt;<br>&lt;dependency&gt;<br>    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;<br>    &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt;<br>&lt;/dependency&gt;<br>&lt;dependency&gt;<br>    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;<br>    &lt;artifactId&gt;spring-boot-starter-thymeleaf&lt;/artifactId&gt;<br>&lt;/dependency&gt;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>在登录页面添加一个<strong>隐藏域</strong></li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs html">&lt;input<br>type=&quot;hidden&quot; th:if=&quot;$&#123;_csrf&#125;!=null&quot; th:value=&quot;$&#123;_csrf.token&#125;&quot; name=&quot;_csrf&quot;/&gt;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>关闭安全配置的类中的 csrf</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-comment">// http.csrf().disable();</span><br></code></pre></div></td></tr></table></figure>
<hr>
<h4 id="「原理」"><a href="#「原理」" class="headerlink" title="「原理」"></a>「原理」</h4><p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210414211832498.png" srcset="/img/loading.gif" lazyload></p>
<ol>
<li>生成 csrfToken 保存到 HttpSession 或者 Cookie 中</li>
</ol>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210414220149644.png" srcset="/img/loading.gif" lazyload></p>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">CsrfToken</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Serializable</span> </span>&#123;<br>    <span class="hljs-function">String <span class="hljs-title">getHeaderName</span><span class="hljs-params">()</span></span>;<br>    <span class="hljs-function">String <span class="hljs-title">getParameterName</span><span class="hljs-params">()</span></span>;<br>    <span class="hljs-function">String <span class="hljs-title">getToken</span><span class="hljs-params">()</span></span>;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ul>
<li><code>SaveOnAccessCsrfToken</code> 类有个接口 <code>CsrfTokenRepository</code></li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SaveOnAccessCsrfToken</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">CsrfToken</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">transient</span> CsrfTokenRepository tokenRepository;<br></code></pre></div></td></tr></table></figure>
<ul>
<li>其实现类 <code>HttpSessionCsrfTokenRepository</code>  <code>CookieCsrfTokenRepository</code></li>
</ul>
<p><img src="https://gitee.com/hypocrite30/ImgBed/raw/master/img/SpringSecurity/image-20210414220605226.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li><code>CookieCsrfTokenRepository</code> 截取部分</li>
</ul>
<figure class="highlight reasonml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs reasonml">public final <span class="hljs-keyword">class</span> CookieCsrfTokenRepository implements CsrfTokenRepository &#123;<br>    <span class="hljs-keyword">private</span> String parameterName = <span class="hljs-string">&quot;_csrf&quot;</span>;<br>    <br>    public CsrfToken generate<span class="hljs-constructor">Token(HttpServletRequest <span class="hljs-params">request</span>)</span> &#123;<br>        return <span class="hljs-keyword">new</span> <span class="hljs-constructor">DefaultCsrfToken(<span class="hljs-params">this</span>.<span class="hljs-params">headerName</span>, <span class="hljs-params">this</span>.<span class="hljs-params">parameterName</span>, <span class="hljs-params">this</span>.<span class="hljs-params">createNewToken</span>()</span>);<br>    &#125;<br>    <br>    <span class="hljs-keyword">private</span> String create<span class="hljs-constructor">NewToken()</span> &#123;<br>        return <span class="hljs-module-access"><span class="hljs-module"><span class="hljs-identifier">UUID</span>.</span></span>random<span class="hljs-constructor">UUID()</span>.<span class="hljs-keyword">to</span><span class="hljs-constructor">String()</span>;<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>
<ol start="2">
<li>请求到来时，从请求中提取 csrfToken，和保存的 csrfToken 做比较，进而判断当前请求是否合法。主要通过 <code>CsrfFilter</code> 过滤器来完成。</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CsrfFilter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">OncePerRequestFilter</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> CsrfTokenRepository tokenRepository;<br>    <br>    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doFilterInternal</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)</span> <span class="hljs-keyword">throws</span> ServletException, IOException </span>&#123;<br>        request.setAttribute(HttpServletResponse.class.getName(), response);<br>        CsrfToken csrfToken = <span class="hljs-keyword">this</span>.tokenRepository.loadToken(request);<br>        <span class="hljs-keyword">boolean</span> missingToken = csrfToken == <span class="hljs-keyword">null</span>;<br>        <span class="hljs-keyword">if</span> (missingToken) &#123;<br>            csrfToken = <span class="hljs-keyword">this</span>.tokenRepository.generateToken(request);<br>            <span class="hljs-keyword">this</span>.tokenRepository.saveToken(csrfToken, request, response);<br>        &#125;<br><br>        request.setAttribute(CsrfToken.class.getName(), csrfToken);<br>        <span class="hljs-comment">// key: _csrf  value: token</span><br>        request.setAttribute(csrfToken.getParameterName(), csrfToken);<br>        <span class="hljs-comment">// 验证是否匹配正确</span><br>        <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.requireCsrfProtectionMatcher.matches(request)) &#123; <br>            filterChain.doFilter(request, response);<br>        &#125;<br>        ...<br></code></pre></div></td></tr></table></figure>




<h3 id="基于微服务和jwt待续。。。"><a href="#基于微服务和jwt待续。。。" class="headerlink" title="基于微服务和jwt待续。。。"></a>基于微服务和jwt待续。。。</h3><blockquote>
<p>鸣谢：</p>
<p><a target="_blank" rel="noopener" href="https://docs.spring.io/spring-security/site/docs/5.3.4.RELEASE/reference/html5/#servlet-hello">https://docs.spring.io/spring-security/site/docs/5.3.4.RELEASE/reference/html5/#servlet-hello</a></p>
<p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1VE411h7aL">https://www.bilibili.com/video/BV1VE411h7aL</a></p>
<p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV15a411A7kP?from=search&amp;seid=12610921816944973603">https://www.bilibili.com/video/BV15a411A7kP?from=search&amp;seid=12610921816944973603</a></p>
</blockquote>

            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/Security/">Security</a>
                    
                  </div>
                
                
              </div>
              
                <p class="note note-warning">
                  
                    本博客所有文章除特别声明外，均采用 <a target="_blank" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" rel="nofollow noopener noopener">CC BY-SA 4.0 协议</a> ，转载请注明出处！
                  
                </p>
              
              
                <div class="post-prevnext">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2021/04/16/DesignPatterns/DesignPatterns/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">DesignPatterns</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2021/04/05/SpringBoot/SpringBoot/">
                        <span class="hidden-mobile">SpringBoot 2.3.4</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
  </main>

  <footer class="text-center mt-5 py-3">
  <div class="footer-content">
     © 2019-2021 
  </div>
  
  <div class="statistics">
    
    

    
      
        <!-- 不蒜子统计PV -->
        <span id="busuanzi_container_site_pv" style="display: none">
            总访问量 
            <span id="busuanzi_value_site_pv"></span>
             次
          </span>
      
      
        <!-- 不蒜子统计UV -->
        <span id="busuanzi_container_site_uv" style="display: none">
            总访客数 
            <span id="busuanzi_value_site_uv"></span>
             人
          </span>
      
    
  </div>


  

  
</footer>


  <!-- SCRIPTS -->
  
  <script  src="https://cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js" ></script>
<script  src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" ></script>
<script  src="/js/debouncer.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  
    <script  src="/js/img-lazyload.js" ></script>
  



  



  <script  src="https://cdn.jsdelivr.net/npm/tocbot@4.12.0/dist/tocbot.min.js" ></script>



  <script  src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js" ></script>



  <script  src="https://cdn.jsdelivr.net/npm/anchor-js@4.3.0/anchor.min.js" ></script>



  <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2.0.6/dist/clipboard.min.js" ></script>



  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>




  <script  src="https://cdn.jsdelivr.net/npm/typed.js@2.0.11/lib/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var title = document.getElementById('subtitle').title;
      
      typing(title)
      
    })(window, document);
  </script>



  <script  src="/js/local-search.js" ></script>
  <script>
    (function () {
      var path = "/local-search.xml";
      $('#local-search-input').on('click', function() {
        searchFunc(path, 'local-search-input', 'local-search-result');
      });
      $('#modalSearch').on('shown.bs.modal', function() {
        $('#local-search-input').focus();
      });
    })()
  </script>





  

  
    <!-- MathJax -->
    <script>
      MathJax = {
        tex: {
          inlineMath: [['$', '$'], ['\\(', '\\)']]
        },
        options: {
          renderActions: {
            findScript: [10, doc => {
              document.querySelectorAll('script[type^="math/tex"]').forEach(node => {
                const display = !!node.type.match(/; *mode=display/);
                const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display);
                const text = document.createTextNode('');
                node.parentNode.replaceChild(text, node);
                math.start = { node: text, delim: '', n: 0 };
                math.end = { node: text, delim: '', n: 0 };
                doc.math.push(math);
              });
            }, '', false],
            insertedScript: [200, () => {
              document.querySelectorAll('mjx-container').forEach(node => {
                let target = node.parentNode;
                if (target.nodeName.toLowerCase() === 'li') {
                  target.parentNode.classList.add('has-jax');
                }
              });
            }, '', false]
          }
        }
      };
    </script>

    <script async src="https://cdn.jsdelivr.net/npm/mathjax@3.1.2/es5/tex-svg.js" ></script>

  











<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>


</body>
</html>
